WORD PTR

Pointed Development

wordptr.libwpd – Hooking the Main Loop

| Comments

It’s (slowly) getting somewhere.

I updated the libwpd configuration settings in wordptr.libwpd to support a client override of the default daemon loop. This method gets injected into the daemon start method on reconfiguration.

There’s a little more work to do in this space, but here’s a brief outline…

First, the following typedef was added for the hook signature:

1
2
3
4
5
/* start method hook signature */
  typedef void (*wp_daemon_start_method_fn)(const struct wp_daemonizer *);

  /* Example in client code */
  void daemon_start(const wp_daemonizer_t *self);

The wp_daemon_start_method_fn typedef is utilized by the internal configuration class with the following getters and setters:

1
2
wp_daemon_start_method_fn (*get_daemon_start_method)(const struct wp_configuration *self);
  void (*set_daemon_start_method)(const struct wp_configuration *self, wp_daemon_start_method_fn fn);

Finally, the hook is installed within the client reconfiguration method like so:

1
2
3
static void reconfigure_daemon(const struct wp_daemonizer *daemon, const wp_configuration_pt config) {
  config->set_daemon_start_method(config, &daemon_start);
}

If the hook is not installed, the daemon creates its own loop: It sits in a perpetual wait state, listening for signals. By overriding the main loop with your own daemon_start method, you can alter the default run loop.

The current default run loop looks something like this (see the latest commit on GitHub for wp_daemonizer.c, method wp_daemonizer_start):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static wp_status_t wp_daemonizer_start(const wp_daemonizer_t *self) {
  assert(self); /* make compiler happy */
  sigset_t mask, oldmask;
  wp_daemon_start_method_fn start_fn = self->data->config->get_daemon_start_method(self->data->config);


  if(start_fn != NULL) {
    start_fn(self);
  } else {
    sigemptyset(&mask);
    sigaddset(&mask, SIGUSR1);
    sigprocmask(SIG_BLOCK, &mask, &oldmask);

    while(true) {
      sigsuspend(&oldmask);
    }
    sigprocmask(SIG_UNBLOCK, &mask, NULL);
  }

  return WP_SUCCESS;
}

Note that in the override case, the sigsuspend method is never called. Consider a similar pattern in your own main loop or you’ll eat CPU cycles.

Have fun.

Comments