static LIST_INIT(dso_registry);
/* Structure to keep parsed register variables from client message. */
-struct register_data {
+struct message_data {
char *dso_name; /* Name of DSO. */
char *device_path; /* Mapped device path. */
union {
char *str; /* Events string as fetched from message. */
enum event_type field; /* Events bitfield. */
} events;
+ struct daemon_message *msg; /* Pointer to message buffer. */
};
/*
static LIST_INIT(thread_registry);
/* Allocate/free the status structure for a monitoring thread. */
-static struct thread_status *alloc_thread_status(struct register_data *data,
+static struct thread_status *alloc_thread_status(struct message_data *data,
struct dso_data *dso_data)
{
struct thread_status *ret = (typeof(ret)) dbg_malloc(sizeof(*ret));
}
/* Allocate/free DSO data. */
-static struct dso_data *alloc_dso_data(struct register_data *data)
+static struct dso_data *alloc_dso_data(struct message_data *data)
{
struct dso_data *ret = (typeof(ret)) dbg_malloc(sizeof(*ret));
}
/* Fetch a string off src and duplicate it into *dest. */
+/* FIXME: move to separate module to share with the client lib. */
static const char delimiter = ' ';
static char *fetch_string(char **src)
{
- char *p, *ret;
+ char *p, *ret = NULL;
- if ((p = strchr(*src, delimiter)))
+ if ((p = strchr(*src, delimiter))) {
*p = 0;
- if ((ret = dbg_strdup(*src)))
- *src += strlen(ret) + 1;
+ if ((ret = dbg_strdup(*src)))
+ *src += strlen(ret) + 1;
- if (p)
- *p = delimiter;
+ if (p)
+ *p = delimiter;
+ } else if (*src)
+ ret = dbg_strdup(*src);
return ret;
}
/* Free message memory. */
-static void free_message(struct register_data *register_data)
+static void free_message(struct message_data *message_data)
{
- if (register_data->dso_name)
- dbg_free(register_data->dso_name);
+ if (message_data->dso_name)
+ dbg_free(message_data->dso_name);
- if (register_data->device_path)
- dbg_free(register_data->device_path);
+ if (message_data->device_path)
+ dbg_free(message_data->device_path);
}
/* Parse a register message from the client. */
-static int parse_message(struct register_data *register_data, char *msg)
+static int parse_message(struct message_data *message_data)
{
- char *p = msg;
+ char *p = message_data->msg->msg;
- memset(register_data, 0, sizeof(*register_data));
+ memset(message_data, 0, sizeof(*message_data));
/*
* Retrieve application identifier, mapped device
* path and events # string from message.
*/
- if ((register_data->dso_name = fetch_string(&p)) &&
- (register_data->device_path = fetch_string(&p)) &&
- (register_data->events.str = fetch_string(&p))) {
- enum event_type i = atoi(register_data->events.str);
-
- /* Free string representaion of events. Not needed an more. */
- dbg_free(register_data->events.str);
- register_data->events.field = i;
+ if ((message_data->dso_name = fetch_string(&p)) &&
+ (message_data->device_path = fetch_string(&p)) &&
+ (message_data->events.str = fetch_string(&p))) {
+ if (message_data->events.str) {
+ enum event_type i = atoi(message_data->events.str);
+
+ /*
+ * Free string representaion of events.
+ * Not needed an more.
+ */
+ dbg_free(message_data->events.str);
+ message_data->events.field = i;
+ }
return 1;
}
- free_message(register_data);
+ free_message(message_data);
return 0;
};
*
* Mutex must be hold when calling this.
*/
-static struct thread_status *lookup_thread_status(struct register_data *data)
+static struct thread_status *lookup_thread_status(struct message_data *data)
{
struct thread_status *thread;
{
size_t len;
- if ((len = strlen(params)) && params[len - 1] == 'F') {
+ if ((len = strlen(params)) &&
+ params[len - 1] == 'F') {
thread->current_events |= DEVICE_ERROR;
return 1;
}
&target_type, ¶ms);
log_print("%s: %s\n", __func__, params);
- if (error_detected(thread, params))
+ if ((ret = error_detected(thread, params)))
break;
} while(next);
}
}
/* Device monitoring thread. */
-void *monitor_thread(void *arg)
+static void *monitor_thread(void *arg)
{
struct thread_status *thread = arg;
/* REMOVEME: */
log_print("%s: cycle on %s\n", __func__, thread->device_path);
- /* Check against filter. */
+ /*
+ * Check against filter.
+ *
+ * If there's current events delivered from event_wait() AND
+ * the device got registered for those events AND
+ * those events haven't been processed yet, call
+ * the DSO's process_event() handler.
+ */
if (thread->events &
thread->current_events &
~thread->processed_events) {
}
/* Find DSO data. */
-static struct dso_data *lookup_dso(struct register_data *data)
+static struct dso_data *lookup_dso(struct message_data *data)
{
struct dso_data *dso_data, *ret = NULL;
list_iterate_items(dso_data, &dso_registry) {
if (!strcmp(data->dso_name, dso_data->dso_name)) {
+ lib_get(dso_data);
ret = dso_data;
- lib_get(ret);
break;
}
}
}
/* Create a DSO file name based on its name. */
-static char *create_dso_file(char *dso_name)
+static char *create_dso_file_name(char *dso_name)
{
char *ret;
static char *prefix = "libdmeventd_";
}
/* Load an application specific DSO. */
-static struct dso_data *load_dso(struct register_data *data)
+static struct dso_data *load_dso(struct message_data *data)
{
void *dl;
struct dso_data *ret = NULL;
char *dso_file;
- if (!(dso_file = create_dso_file(data->dso_name)))
+ if (!(dso_file = create_dso_file_name(data->dso_name)))
return NULL;
if (!(dl = dlopen(dso_file, RTLD_NOW)))
* Only one caller at a time here, because we use a FIFO and lock
* it against multiple accesses.
*/
-static int register_for_event(char *msg)
+static int register_for_event(struct message_data *message_data)
{
int ret = 0;
- struct register_data register_data;
struct thread_status *thread, *thread_new;
struct dso_data *dso_data;
- /* Parse the register message and find/load the appropriate DSO. */
- if (!parse_message(®ister_data, msg))
- return -EINVAL;
-
- if (!device_exists(register_data.device_path)) {
+ if (!device_exists(message_data->device_path)) {
stack;
ret = -ENODEV;
goto out;
}
- if (!(dso_data = lookup_dso(®ister_data)) &&
- !(dso_data = load_dso(®ister_data))) {
+ if (!(dso_data = lookup_dso(message_data)) &&
+ !(dso_data = load_dso(message_data))) {
stack;
ret = -ELIBACC;
goto out;
}
/* Preallocate thread status struct to avoid deadlock. */
- if (!(thread_new = alloc_thread_status(®ister_data, dso_data))) {
+ if (!(thread_new = alloc_thread_status(message_data, dso_data))) {
stack;
ret = -ENOMEM;
goto out;
lock_mutex();
- if ((thread = lookup_thread_status(®ister_data)))
+ if ((thread = lookup_thread_status(message_data)))
ret = -EPERM;
else {
thread = thread_new;
}
/* Or event # into events bitfield. */
- thread->events |= register_data.events.field;
+ thread->events |= message_data->events.field;
unlock_mutex();
free_thread_status(thread_new);
out:
- free_message(®ister_data);
+ free_message(message_data);
return ret;
}
*
* Only one caller at a time here as with register_for_event().
*/
-static int unregister_for_event(char *msg)
+static int unregister_for_event(struct message_data *message_data)
{
int ret = 0;
- struct register_data register_data;
struct thread_status *thread;
- if (!parse_message(®ister_data, msg))
- return -EINVAL;
-
/*
* Clear event in bitfield and deactivate
* monitoring thread in case bitfield is 0.
*/
-
lock_mutex();
- if (!(thread = lookup_thread_status(®ister_data))) {
+ if (!(thread = lookup_thread_status(message_data))) {
unlock_mutex();
ret = -ESRCH;
goto out;
}
- thread->events &= ~register_data.events.field;
+ thread->events &= ~message_data->events.field;
/*
* In case there's no events to monitor on this
out:
- free_message(®ister_data);
+ free_message(message_data);
return ret;
}
+/*
+ * Get next registered device.
+ *
+ * Only one caller at a time here as with register_for_event().
+ */
+static int next_registered_device(struct message_data *message_data)
+{
+ struct daemon_message *msg = message_data->msg;
+
+ snprintf(msg->msg, sizeof(msg->msg), "%s %s %u",
+ message_data->dso_name, message_data->device_path,
+ message_data->events.field);
+
+ return 0;
+}
+
+static struct list *device_iter = NULL;
+static int get_next_registered_device(struct message_data *message_data)
+{
+ struct thread_status *thread;
+
+ if (!device_iter) {
+ if (list_empty(&thread_registry))
+ return -ENOENT;
+
+ device_iter = thread_registry.n;
+ } else if (device_iter == &thread_registry) {
+ device_iter = NULL;
+ return -ENOENT;
+ }
+
+ thread = list_item(device_iter, struct thread_status);
+ device_iter = device_iter->n;
+
+log_print("%s: device_path: %s\n", __func__, message_data->device_path);
+ if (message_data->device_path &&
+ !strcmp(thread->device_path, message_data->device_path))
+ return next_registered_device(message_data);
+
+log_print("%s: dso_name: %s\n", __func__, message_data->dso_name);
+ if (message_data->dso_name &&
+ !strcmp(thread->dso_data->dso_name, message_data->dso_name))
+ return next_registered_device(message_data);
+
+ return next_registered_device(message_data);
+}
+
/* Initialize a fifos structure with path names. */
static void init_fifos(struct fifos *fifos)
{
}
/* Process a request passed from the communication thread. */
-static int _process_request(struct daemon_message *msg)
+static int do_process_request(struct daemon_message *msg)
{
int ret;
+ static struct message_data message_data;
+
+ /* Parse the message. */
+ message_data.msg = msg;
+ if (msg->opcode.cmd != CMD_ACTIVE &&
+ !parse_message(&message_data)) {
+ stack;
+ return -EINVAL;
+ }
/* Check the request type. */
switch (msg->opcode.cmd) {
case CMD_ACTIVE:
ret = 0;
break;
-
case CMD_REGISTER_FOR_EVENT:
- ret = register_for_event(msg->msg);
+ ret = register_for_event(&message_data);
break;
-
case CMD_UNREGISTER_FOR_EVENT:
- ret = unregister_for_event(msg->msg);
+ ret = unregister_for_event(&message_data);
+ break;
+ case CMD_GET_NEXT_REGISTERED_DEVICE:
+ ret = get_next_registered_device(&message_data);
break;
}
return ret;
}
+/* Only one caller at a time. */
static void process_request(struct fifos *fifos, struct daemon_message *msg)
{
/* Read the request from the client. */
return;
}
- msg->opcode.status = _process_request(msg);
+ msg->opcode.status = do_process_request(msg);
memset(&msg->msg, 0, sizeof(msg->msg));
if (!client_write(fifos, msg))
*lf2 = -1;
}
+/* Fetch a string off src and duplicate it into *dest. */
+/* FIXME: move to seperate module to share with the daemon. */
+static const char delimiter = ' ';
+static char *fetch_string(char **src)
+{
+ char *p, *ret;
+
+ if ((p = strchr(*src, delimiter)))
+ *p = 0;
+
+ if ((ret = strdup(*src)))
+ *src += strlen(ret) + 1;
+
+ if (p)
+ *p = delimiter;
+
+ return ret;
+}
+
+/* Parse a device message from the daemon. */
+static int parse_message(struct daemon_message *msg, char **dso_name,
+ char **device, enum event_type *events)
+{
+ char *p = msg->msg;
+
+ if ((*dso_name = fetch_string(&p)) &&
+ (*device = fetch_string(&p))) {
+ *events = atoi(p);
+
+ return 0;
+ }
+
+ return -ENOMEM;
+}
+
/* Read message from daemon. */
static int daemon_read(struct fifos *fifos, struct daemon_message *msg)
{
return bytes == sizeof(*msg);
}
-static int daemon_talk(struct fifos *fifos, int cmd,
- char *dso_name, char *device, enum event_type events)
+static int daemon_talk(struct fifos *fifos, struct daemon_message *msg,
+ int cmd, char *dso_name, char *device,
+ enum event_type events)
{
- struct daemon_message msg;
-
if (!_lock(LOCKFILE, &lf)) {
stack;
return -EPERM;
}
- memset(&msg, 0, sizeof(msg));
+ memset(msg, 0, sizeof(*msg));
/*
* Set command and pack the arguments
* into ASCII message string.
*/
- msg.opcode.cmd = cmd;
- snprintf(msg.msg, sizeof(msg.msg), "%s %s %u",
+ msg->opcode.cmd = cmd;
+ snprintf(msg->msg, sizeof(msg->msg), "%s %s %u",
dso_name, device, events);
/*
* Write command and message to and
* read status return code from daemon.
*/
- if (!daemon_write(fifos, &msg)) {
+ if (!daemon_write(fifos, msg)) {
stack;
return -EIO;
}
- if (!daemon_read(fifos, &msg)) {
+ if (!daemon_read(fifos, msg)) {
stack;
return -EIO;
}
_unlock(LOCKFILE, &lf);
- return msg.opcode.status;
+ return msg->opcode.status;
}
/* Fork and exec the daemon. */
/* Wait for daemon to startup. */
static int pf = -1;
+
static int daemon_startup(void)
{
int ret, retry = 10;
}
/* Handle the event (de)registration call and return negative error codes. */
-static int do_event(int cmd, char *dso_name, char *device,
- enum event_type events)
+static int do_event(int cmd, struct daemon_message *msg,
+ char *dso_name, char *device, enum event_type events)
{
int ret;
struct fifos fifos;
- if (!device_exists(device))
- return -ENODEV;
-
if (!init_client(&fifos)) {
stack;
return -ESRCH;
}
- if ((ret = daemon_talk(&fifos, cmd, dso_name, device, events)) < 0)
+ if ((ret = daemon_talk(&fifos, msg, cmd, dso_name, device, events)) < 0)
stack;
return ret;
/* External library interface. */
int dm_register_for_event(char *dso_name, char *device, enum event_type events)
{
- return do_event(CMD_REGISTER_FOR_EVENT, dso_name, device, events);
+ struct daemon_message msg;
+
+ if (!device_exists(device))
+ return -ENODEV;
+
+ return do_event(CMD_REGISTER_FOR_EVENT, &msg, dso_name, device, events);
+}
+
+int dm_unregister_for_event(char *dso_name, char *device,
+ enum event_type events)
+{
+ struct daemon_message msg;
+
+ if (!device_exists(device))
+ return -ENODEV;
+
+ return do_event(CMD_UNREGISTER_FOR_EVENT, &msg, dso_name,
+ device, events);
}
-int dm_unregister_for_event(char *dso_name, char *device, uint32_t events)
+int dm_get_next_registered_device(char **dso_name, char **device,
+ enum event_type *events)
{
- return do_event(CMD_UNREGISTER_FOR_EVENT, dso_name, device, events);
+ int ret;
+ struct daemon_message msg;
+
+ if (!(ret = do_event(CMD_GET_NEXT_REGISTERED_DEVICE, &msg,
+ *dso_name, *device, *events)))
+ ret = parse_message(&msg, dso_name, device, events);
+
+ return ret;
}
/*