Skip to content

Commit

Permalink
[mms-handler-dbus] Made D-Bus calls to MMS handler asynchronous
Browse files Browse the repository at this point in the history
This eliminates any chance of an inter-process deadlock in case
if MMS handler and the caller of mms-engine is the same component
(which is the case with commhistoryd).
  • Loading branch information
monich committed Sep 11, 2014
1 parent 2a1a37b commit c40bed2
Show file tree
Hide file tree
Showing 15 changed files with 1,069 additions and 384 deletions.
370 changes: 295 additions & 75 deletions mms-handler-dbus/src/mms_handler_dbus.c

Large diffs are not rendered by default.

107 changes: 91 additions & 16 deletions mms-lib/include/mms_handler.h
Expand Up @@ -56,36 +56,77 @@ typedef enum _mmm_delivery_status {
/* Read status */
typedef MMSReadStatus MMS_READ_STATUS;

/* Handler event callback */
typedef void
(*mms_handler_event_fn)(
MMSHandler* handler,
void* param);

/* Asynchronous incoming message notification. Non-empty message id means
* that we start download the message immediately, empty string means that
* download is postponed, NULL id means that an error has occured. */
typedef struct mms_handler_message_notify_call MMSHandlerMessageNotifyCall;
typedef void
(*mms_handler_message_notify_complete_fn)(
MMSHandlerMessageNotifyCall* call,
const char* id,
void* param);

/* Asynchronous message received notification. Note that the files associated
* with MMSMessage must not be deleted until after the call completes. The
* call context is carrying a reference to MMSMessage with it, that should
* take care of it even if the caller drops its reference immediately after
* submitting the call. */
typedef struct mms_handler_message_received_call MMSHandlerMessageReceivedCall;
typedef void
(*mms_handler_message_received_complete_fn)(
MMSHandlerMessageReceivedCall* call,
MMSMessage* msg,
gboolean ok,
void* param);

/* Instance */
struct mms_handler {
GObject object;
int busy;
};

/* Class */
typedef struct mms_handler_class {
GObjectClass parent;

/* New incoming message notification. Returns the handler message id
* to start download immediately, NULL or empty string to postpone it. */
char* (*fn_message_notify)(
/* New incoming message notification (cancellable) */
MMSHandlerMessageNotifyCall* (*fn_message_notify)(
MMSHandler* handler, /* Handler instance */
const char* imsi, /* Subscriber identity */
const char* from, /* Sender's phone number */
const char* subject, /* Subject (optional) */
time_t expiry, /* Message expiry time */
GBytes* push); /* Raw push message */
GBytes* push, /* Raw push message */
mms_handler_message_notify_complete_fn cb,
void* param);

void (*fn_message_notify_cancel)(
MMSHandler* handler,
MMSHandlerMessageNotifyCall* call);

/* Message has been successfully received (cancellable) */
MMSHandlerMessageReceivedCall* (*fn_message_received)(
MMSHandler* handler, /* Handler instance */
MMSMessage* msg, /* Decoded message */
mms_handler_message_received_complete_fn cb,
void* param);

void (*fn_message_received_cancel)(
MMSHandler* handler,
MMSHandlerMessageReceivedCall* call);

/* Sets the receive state */
gboolean (*fn_message_receive_state_changed)(
MMSHandler* handler, /* Handler instance */
const char* id, /* Handler record id */
MMS_RECEIVE_STATE state); /* Receive state */

/* Message has been successfully received */
gboolean (*fn_message_received)(
MMSHandler* handler, /* Handler instance */
MMSMessage* msg); /* Decoded message */

/* Sets the send state */
gboolean (*fn_message_send_state_changed)(
MMSHandler* handler, /* Handler instance */
Expand Down Expand Up @@ -127,26 +168,40 @@ void
mms_handler_unref(
MMSHandler* handler);

char*
MMSHandlerMessageNotifyCall*
mms_handler_message_notify(
MMSHandler* handler, /* Handler instance */
const char* imsi, /* Subscriber identity */
const char* from, /* Sender's phone number */
const char* subject, /* Subject (optional) */
time_t expiry, /* Message expiry time */
GBytes* push); /* Raw push message */
GBytes* push, /* Raw push message */
mms_handler_message_notify_complete_fn cb,
void* param);

void
mms_handler_message_notify_cancel(
MMSHandler* handler,
MMSHandlerMessageNotifyCall* call);

MMSHandlerMessageReceivedCall*
mms_handler_message_received(
MMSHandler* handler, /* Handler instance */
MMSMessage* msg, /* Decoded message */
mms_handler_message_received_complete_fn cb,
void* param);

void
mms_handler_message_received_cancel(
MMSHandler* handler,
MMSHandlerMessageReceivedCall* call);

gboolean
mms_handler_message_receive_state_changed(
MMSHandler* handler, /* Handler instance */
const char* id, /* Handler record id */
MMS_RECEIVE_STATE state); /* Receive state */

gboolean
mms_handler_message_received(
MMSHandler* handler, /* Handler instance */
MMSMessage* msg); /* Decoded message */

gboolean
mms_handler_message_send_state_changed(
MMSHandler* handler, /* Handler instance */
Expand Down Expand Up @@ -175,6 +230,26 @@ mms_handler_read_report(
const char* recipient, /* Recipient's phone number */
MMS_READ_STATUS rs); /* Read status */

void
mms_handler_busy_update(
MMSHandler* handler, /* Handler instance */
int change); /* Normally +1 or -1 */

gulong
mms_handler_add_done_callback(
MMSHandler* handler, /* Handler instance */
mms_handler_event_fn fn, /* Callback function */
void* param); /* Callback parameter */

void
mms_handler_remove_callback(
MMSHandler* handler, /* Handler instance */
gulong handler_id); /* Idenfies the callback to remove */

#define mms_handler_busy(handler) ((handler) && ((handler)->busy > 0))
#define mms_handler_busy_inc(handler) mms_handler_busy_update(handler,1)
#define mms_handler_busy_dec(handler) mms_handler_busy_update(handler,-1)

#endif /* JOLLA_MMS_HANDLER_H */

/*
Expand Down
21 changes: 20 additions & 1 deletion mms-lib/src/mms_dispatcher.c
Expand Up @@ -43,6 +43,7 @@ struct mms_dispatcher {
GQueue* tasks;
guint next_run_id;
guint network_idle_id;
gulong handler_done_id;
gboolean started;
};

Expand Down Expand Up @@ -261,7 +262,8 @@ mms_dispatcher_is_active(
MMSDispatcher* disp)
{
return disp && (mms_connection_is_active(disp->connection) ||
disp->active_task || !g_queue_is_empty(disp->tasks));
mms_handler_busy(disp->handler) || disp->active_task ||
!g_queue_is_empty(disp->tasks));
}

/**
Expand Down Expand Up @@ -639,6 +641,20 @@ mms_dispatcher_delegate_task_state_changed(
}
}

/**
* Handler state callback
*/
static
void
mms_dispatcher_handler_done(
MMSHandler* handler,
void* param)
{
MMSDispatcher* disp = param;
MMS_VERBOSE("Handler has nothing to do");
mms_dispatcher_next_run_schedule(disp);
}

/**
* Creates the dispatcher object. Caller must clal mms_dispatcher_unref
* when it no longer needs it.
Expand All @@ -661,6 +677,8 @@ mms_dispatcher_new(
mms_dispatcher_delegate_task_state_changed;
disp->connection_delegate.fn_connection_state_changed =
mms_dispatcher_delegate_connection_state_changed;
disp->handler_done_id = mms_handler_add_done_callback(handler,
mms_dispatcher_handler_done, disp);
return disp;
}

Expand All @@ -676,6 +694,7 @@ mms_dispatcher_finalize(
const char* root_dir = disp->settings->config->root_dir;
char* msg_dir = g_strconcat(root_dir, "/" MMS_MESSAGE_DIR "/", NULL);
MMS_VERBOSE_("");
mms_handler_remove_callback(disp->handler, disp->handler_done_id);
mms_dispatcher_drop_connection(disp);
while ((task = g_queue_pop_head(disp->tasks)) != NULL) {
task->delegate = NULL;
Expand Down

0 comments on commit c40bed2

Please sign in to comment.