Commit 9cc93657 authored by Pekka Pessi's avatar Pekka Pessi

su_port: improved virtualization. Moved public clone functions to su_port.c.

There are now two different preferred port implementations: one used with
su_root_create() and another with su_clone_start().

darcs-hash:20070202155042-65a35-90517d7a3f3dbbd7b0ce8c9169a40915d75e139b.gz
parent 8d90608d
...@@ -183,7 +183,7 @@ int su_base_port_getmsgs(su_port_t *self) ...@@ -183,7 +183,7 @@ int su_base_port_getmsgs(su_port_t *self)
} }
int su_base_port_getmsgs_from_port(su_port_t *self, su_port_t *from) int su_base_port_getmsgs_from(su_port_t *self, su_port_t *from)
{ {
su_msg_t *msg, *selected; su_msg_t *msg, *selected;
su_msg_t **next = &self->sup_head, **tail= &selected; su_msg_t **next = &self->sup_head, **tail= &selected;
...@@ -509,7 +509,7 @@ static void su_base_port_clone_break(su_root_magic_t *m, ...@@ -509,7 +509,7 @@ static void su_base_port_clone_break(su_root_magic_t *m,
su_msg_r msg, su_msg_r msg,
su_msg_arg_t *arg); su_msg_arg_t *arg);
int su_base_port_start(su_root_t *parent, int su_base_port_start_shared(su_root_t *parent,
su_clone_r return_clone, su_clone_r return_clone,
su_root_magic_t *magic, su_root_magic_t *magic,
su_root_init_f init, su_root_init_f init,
......
...@@ -108,6 +108,7 @@ static int su_epoll_port_eventmask(su_port_t *self, ...@@ -108,6 +108,7 @@ static int su_epoll_port_eventmask(su_port_t *self,
int events); int events);
static int su_epoll_port_multishot(su_port_t *self, int multishot); static int su_epoll_port_multishot(su_port_t *self, int multishot);
static int su_epoll_port_wait_events(su_port_t *self, su_duration_t tout); static int su_epoll_port_wait_events(su_port_t *self, su_duration_t tout);
static char const *su_epoll_port_name(su_port_t const *self);
su_port_vtable_t const su_epoll_port_vtable[1] = su_port_vtable_t const su_epoll_port_vtable[1] =
{{ {{
...@@ -135,12 +136,17 @@ su_port_vtable_t const su_epoll_port_vtable[1] = ...@@ -135,12 +136,17 @@ su_port_vtable_t const su_epoll_port_vtable[1] =
su_base_port_yield, su_base_port_yield,
su_epoll_port_wait_events, su_epoll_port_wait_events,
su_base_port_getmsgs, su_base_port_getmsgs,
su_epoll_port_create, su_base_port_getmsgs_from,
su_pthread_port_start, su_epoll_port_name,
su_base_port_start_shared,
su_pthread_port_wait, su_pthread_port_wait,
su_pthread_port_execute, su_pthread_port_execute,
}}; }};
static char const *su_epoll_port_name(su_port_t const *self)
{
return "epoll";
}
static void su_epoll_port_decref(su_port_t *self, int blocking, char const *who) static void su_epoll_port_decref(su_port_t *self, int blocking, char const *who)
{ {
...@@ -546,6 +552,16 @@ su_port_t *su_epoll_port_create(void) ...@@ -546,6 +552,16 @@ su_port_t *su_epoll_port_create(void)
return self; return self;
} }
int su_epoll_clone_start(su_root_t *parent,
su_clone_r return_clone,
su_root_magic_t *magic,
su_root_init_f init,
su_root_deinit_f deinit)
{
return su_pthreaded_port_start(su_epoll_port_create,
parent, return_clone, magic, init, deinit);
}
#else #else
su_port_t *su_epoll_port_create(void) su_port_t *su_epoll_port_create(void)
...@@ -553,4 +569,15 @@ su_port_t *su_epoll_port_create(void) ...@@ -553,4 +569,15 @@ su_port_t *su_epoll_port_create(void)
return su_poll_port_create(); return su_poll_port_create();
} }
int su_epoll_clone_start(su_root_t *parent,
su_clone_r return_clone,
su_root_magic_t *magic,
su_root_init_f init,
su_root_deinit_f deinit)
{
return su_pthreaded_port_start(su_poll_port_create,
parent, return_clone, magic, init, deinit);
}
#endif /* HAVE_EPOLL */ #endif /* HAVE_EPOLL */
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
#include "config.h" #include "config.h"
#if HAVE_POLL #if HAVE_POLL || HAVE_WIN32
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
...@@ -114,6 +114,7 @@ static int su_poll_port_eventmask(su_port_t *self, ...@@ -114,6 +114,7 @@ static int su_poll_port_eventmask(su_port_t *self,
int events); int events);
static int su_poll_port_multishot(su_port_t *self, int multishot); static int su_poll_port_multishot(su_port_t *self, int multishot);
static int su_poll_port_wait_events(su_port_t *self, su_duration_t tout); static int su_poll_port_wait_events(su_port_t *self, su_duration_t tout);
static char const *su_poll_port_name(su_port_t const *self);
su_port_vtable_t const su_poll_port_vtable[1] = su_port_vtable_t const su_poll_port_vtable[1] =
{{ {{
...@@ -141,12 +142,18 @@ su_port_vtable_t const su_poll_port_vtable[1] = ...@@ -141,12 +142,18 @@ su_port_vtable_t const su_poll_port_vtable[1] =
su_base_port_yield, su_base_port_yield,
su_poll_port_wait_events, su_poll_port_wait_events,
su_base_port_getmsgs, su_base_port_getmsgs,
su_poll_port_create, su_base_port_getmsgs_from,
su_pthread_port_start, su_poll_port_name,
su_base_port_start_shared,
su_pthread_port_wait, su_pthread_port_wait,
su_pthread_port_execute, su_pthread_port_execute,
}}; }};
static char const *su_poll_port_name(su_port_t const *self)
{
return "poll";
}
static void su_poll_port_deinit(void *arg) static void su_poll_port_deinit(void *arg)
{ {
su_port_t *self = arg; su_port_t *self = arg;
...@@ -662,4 +669,14 @@ su_port_t *su_poll_port_create(void) ...@@ -662,4 +669,14 @@ su_port_t *su_poll_port_create(void)
return self; return self;
} }
int su_poll_clone_start(su_root_t *parent,
su_clone_r return_clone,
su_root_magic_t *magic,
su_root_init_f init,
su_root_deinit_f deinit)
{
return su_pthreaded_port_start(su_poll_port_create,
parent, return_clone, magic, init, deinit);
}
#endif /* HAVE_POLL */ #endif /* HAVE_POLL */
This diff is collapsed.
...@@ -133,9 +133,10 @@ typedef struct su_port_vtable { ...@@ -133,9 +133,10 @@ typedef struct su_port_vtable {
/* Extension from >= 1.12.4 */ /* Extension from >= 1.12.4 */
int (*su_port_wait_events)(su_port_t *port, su_duration_t timeout); int (*su_port_wait_events)(su_port_t *port, su_duration_t timeout);
int (*su_port_getmsgs)(su_port_t *port); int (*su_port_getmsgs)(su_port_t *port);
/* Extension from >= 1.12.5 - create a cloned port */ /* Extension from >= 1.12.5 */
su_port_t *(*su_port_create)(void); int (*su_port_getmsgs_from)(su_port_t *port, su_port_t *cloneport);
int (*su_port_start)(su_root_t *parent, char const *(*su_port_name)(su_port_t const *port);
int (*su_port_start_shared)(su_root_t *root,
su_clone_r return_clone, su_clone_r return_clone,
su_root_magic_t *magic, su_root_magic_t *magic,
su_root_init_f init, su_root_init_f init,
...@@ -150,7 +151,15 @@ SOFIAPUBFUN su_port_t *su_port_create(void) ...@@ -150,7 +151,15 @@ SOFIAPUBFUN su_port_t *su_port_create(void)
__attribute__((__malloc__)); __attribute__((__malloc__));
/* Extension from >= 1.12.5 */ /* Extension from >= 1.12.5 */
SOFIAPUBFUN void su_port_prefer(su_port_t *(*implementation)(void));
typedef su_port_t *su_port_create_f(void);
typedef int su_clone_start_f(su_root_t *parent,
su_clone_r return_clone,
su_root_magic_t *magic,
su_root_init_f init,
su_root_deinit_f deinit);
SOFIAPUBFUN void su_port_prefer(su_port_create_f *f, su_clone_start_f *);
SOFIAPUBFUN su_port_t *su_epoll_port_create(void) SOFIAPUBFUN su_port_t *su_epoll_port_create(void)
__attribute__((__malloc__)); __attribute__((__malloc__));
...@@ -159,6 +168,10 @@ SOFIAPUBFUN su_port_t *su_poll_port_create(void) ...@@ -159,6 +168,10 @@ SOFIAPUBFUN su_port_t *su_poll_port_create(void)
SOFIAPUBFUN su_port_t *su_select_port_create(void) SOFIAPUBFUN su_port_t *su_select_port_create(void)
__attribute__((__malloc__)); __attribute__((__malloc__));
SOFIAPUBFUN su_clone_start_f su_epoll_clone_start;
SOFIAPUBFUN su_clone_start_f su_poll_clone_start;
SOFIAPUBFUN su_clone_start_f su_select_clone_start;
SOFIAPUBFUN void su_msg_delivery_report(su_msg_r msg); SOFIAPUBFUN void su_msg_delivery_report(su_msg_r msg);
SOFIAPUBFUN su_duration_t su_timer_next_expires(su_timer_t const * t, SOFIAPUBFUN su_duration_t su_timer_next_expires(su_timer_t const * t,
su_time_t now); su_time_t now);
...@@ -410,11 +423,14 @@ int su_port_getmsgs(su_port_t *self) ...@@ -410,11 +423,14 @@ int su_port_getmsgs(su_port_t *self)
return base->sup_vtable->su_port_getmsgs(self); return base->sup_vtable->su_port_getmsgs(self);
} }
SOFIAPUBFUN int su_port_start(su_root_t *parent, static inline
su_clone_r return_clone, int su_port_getmsgs_from(su_port_t *self, su_port_t *cloneport)
su_root_magic_t *magic, {
su_root_init_f init, su_virtual_port_t *base = (su_virtual_port_t *)self;
su_root_deinit_f deinit);
return base->sup_vtable->su_port_getmsgs_from(self, cloneport);
}
SOFIAPUBFUN void su_port_wait(su_clone_r rclone); SOFIAPUBFUN void su_port_wait(su_clone_r rclone);
SOFIAPUBFUN int su_port_execute(su_task_r const task, SOFIAPUBFUN int su_port_execute(su_task_r const task,
...@@ -468,7 +484,7 @@ SOFIAPUBFUN struct _GSource *su_base_port_gsource(su_port_t *self); ...@@ -468,7 +484,7 @@ SOFIAPUBFUN struct _GSource *su_base_port_gsource(su_port_t *self);
SOFIAPUBFUN su_socket_t su_base_port_mbox(su_port_t *self); SOFIAPUBFUN su_socket_t su_base_port_mbox(su_port_t *self);
SOFIAPUBFUN int su_base_port_send(su_port_t *self, su_msg_r rmsg); SOFIAPUBFUN int su_base_port_send(su_port_t *self, su_msg_r rmsg);
SOFIAPUBFUN int su_base_port_getmsgs(su_port_t *self); SOFIAPUBFUN int su_base_port_getmsgs(su_port_t *self);
SOFIAPUBFUN int su_base_port_getmsgs_from_port(su_port_t *self, SOFIAPUBFUN int su_base_port_getmsgs_from(su_port_t *self,
su_port_t *from); su_port_t *from);
SOFIAPUBFUN void su_base_port_run(su_port_t *self); SOFIAPUBFUN void su_base_port_run(su_port_t *self);
...@@ -489,7 +505,7 @@ SOFIAPUBFUN int su_base_port_multishot(su_port_t *self, int multishot); ...@@ -489,7 +505,7 @@ SOFIAPUBFUN int su_base_port_multishot(su_port_t *self, int multishot);
SOFIAPUBFUN int su_base_port_threadsafe(su_port_t *self); SOFIAPUBFUN int su_base_port_threadsafe(su_port_t *self);
SOFIAPUBFUN int su_base_port_yield(su_port_t *self); SOFIAPUBFUN int su_base_port_yield(su_port_t *self);
SOFIAPUBFUN int su_base_port_start(su_root_t *parent, SOFIAPUBFUN int su_base_port_start_shared(su_root_t *parent,
su_clone_r return_clone, su_clone_r return_clone,
su_root_magic_t *magic, su_root_magic_t *magic,
su_root_init_f init, su_root_init_f init,
...@@ -532,27 +548,33 @@ SOFIAPUBFUN int su_pthread_port_own_thread(su_port_t const *self); ...@@ -532,27 +548,33 @@ SOFIAPUBFUN int su_pthread_port_own_thread(su_port_t const *self);
SOFIAPUBFUN int su_pthread_port_send(su_port_t *self, su_msg_r rmsg); SOFIAPUBFUN int su_pthread_port_send(su_port_t *self, su_msg_r rmsg);
#if 0 /* not yet */
SOFIAPUBFUN su_port_t *su_pthread_port_create(void); SOFIAPUBFUN su_port_t *su_pthread_port_create(void);
SOFIAPUBFUN su_port_t *su_pthread_port_start(su_root_t *parent,
su_clone_r return_clone,
su_root_magic_t *magic,
su_root_init_f init,
su_root_deinit_f deinit);
#endif
SOFIAPUBFUN int su_pthread_port_start(su_root_t *parent, SOFIAPUBFUN int su_pthreaded_port_start(su_port_create_f *create,
su_root_t *parent,
su_clone_r return_clone, su_clone_r return_clone,
su_root_magic_t *magic, su_root_magic_t *magic,
su_root_init_f init, su_root_init_f init,
su_root_deinit_f deinit); su_root_deinit_f deinit);
SOFIAPUBFUN void su_pthread_port_wait(su_clone_r rclone); SOFIAPUBFUN void su_pthread_port_wait(su_clone_r rclone);
SOFIAPUBFUN int su_pthread_port_execute(su_task_r const task, SOFIAPUBFUN int su_pthread_port_execute(su_task_r const task,
int (*function)(void *), void *arg, int (*function)(void *), void *arg,
int *return_value); int *return_value);
#if 0 #if 0
SOFIAPUBFUN int su_pthread_port_pause(su_port_t *self); SOFIAPUBFUN int su_pthread_port_pause(su_port_t *self);
SOFIAPUBFUN int su_pthread_port_resume(su_port_t *self); SOFIAPUBFUN int su_pthread_port_resume(su_port_t *self);
#endif #endif
SOFIAPUBFUN int su_pthread_port_execute(su_task_r const task,
int (*function)(void *), void *arg,
int *return_value);
#else #else
typedef su_base_port_t su_pthread_port_t; typedef su_base_port_t su_pthread_port_t;
...@@ -563,7 +585,6 @@ typedef su_base_port_t su_pthread_port_t; ...@@ -563,7 +585,6 @@ typedef su_base_port_t su_pthread_port_t;
#define su_pthread_port_unlock su_base_port_unlock #define su_pthread_port_unlock su_base_port_unlock
#define su_pthread_port_own_thread su_base_port_own_thread #define su_pthread_port_own_thread su_base_port_own_thread
#define su_pthread_port_send su_base_port_send #define su_pthread_port_send su_base_port_send
#define su_pthread_port_start su_base_port_start
#define su_pthread_port_wait su_base_port_wait #define su_pthread_port_wait su_base_port_wait
#define su_pthread_port_execute su_base_port_execute #define su_pthread_port_execute su_base_port_execute
......
...@@ -205,7 +205,6 @@ void su_pthread_port_deinit(su_port_t *self) ...@@ -205,7 +205,6 @@ void su_pthread_port_deinit(su_port_t *self)
su_base_port_deinit(self); su_base_port_deinit(self);
} }
void su_pthread_port_lock(su_port_t *self, char const *who) void su_pthread_port_lock(su_port_t *self, char const *who)
{ {
PORT_LOCK_DEBUG(("%p at %s locking(%p)...", PORT_LOCK_DEBUG(("%p at %s locking(%p)...",
...@@ -264,6 +263,7 @@ int su_pthread_port_own_thread(su_port_t const *self) ...@@ -264,6 +263,7 @@ int su_pthread_port_own_thread(su_port_t const *self)
struct clone_args struct clone_args
{ {
su_port_create_f*create;
su_root_t *parent; su_root_t *parent;
su_root_magic_t *magic; su_root_magic_t *magic;
su_root_init_f init; su_root_init_f init;
...@@ -287,11 +287,11 @@ struct su_pthread_port_waiting_parent { ...@@ -287,11 +287,11 @@ struct su_pthread_port_waiting_parent {
int waiting; int waiting;
}; };
/** Start a clone task by a pthread. /** Start a clone task running under a pthread.
* *
* @internal * @internal
* *
* Allocates and initializes a sub-task with its own thread. The sub-task is * Allocates and initializes a sub-task with its own pthread. The sub-task is
* represented by clone handle to the rest of the application. The function * represented by clone handle to the rest of the application. The function
* su_clone_start() returns the clone handle in @a return_clone. The clone * su_clone_start() returns the clone handle in @a return_clone. The clone
* handle is used to communicate with the newly created clone task using * handle is used to communicate with the newly created clone task using
...@@ -331,13 +331,15 @@ struct su_pthread_port_waiting_parent { ...@@ -331,13 +331,15 @@ struct su_pthread_port_waiting_parent {
* su_clone_forget(). * su_clone_forget().
* *
*/ */
int su_pthread_port_start(su_root_t *parent, int su_pthreaded_port_start(su_port_create_f *create,
su_root_t *parent,
su_clone_r return_clone, su_clone_r return_clone,
su_root_magic_t *magic, su_root_magic_t *magic,
su_root_init_f init, su_root_init_f init,
su_root_deinit_f deinit) su_root_deinit_f deinit)
{ {
struct clone_args arg = { struct clone_args arg = {
/* create: */ NULL,
/* parent: */ NULL, /* parent: */ NULL,
/* magic: */ NULL, /* magic: */ NULL,
/* init: */ NULL, /* init: */ NULL,
...@@ -351,9 +353,7 @@ int su_pthread_port_start(su_root_t *parent, ...@@ -351,9 +353,7 @@ int su_pthread_port_start(su_root_t *parent,
int thread_created = 0; int thread_created = 0;
pthread_t tid; pthread_t tid;
if (parent && !parent->sur_threading) arg.create = create;
return su_base_port_start(parent, return_clone, magic, init, deinit);
arg.parent = parent; arg.parent = parent;
arg.magic = magic; arg.magic = magic;
arg.init = init; arg.init = init;
...@@ -388,15 +388,13 @@ static void *su_pthread_port_clone_main(void *varg) ...@@ -388,15 +388,13 @@ static void *su_pthread_port_clone_main(void *varg)
{ {
struct clone_args *arg = (struct clone_args *)varg; struct clone_args *arg = (struct clone_args *)varg;
su_task_r task; su_task_r task;
int zap; int zap = 1;
#if SU_HAVE_WINSOCK #if SU_HAVE_WINSOCK
su_init(); su_init();
#endif #endif
task->sut_port = task->sut_port = arg->create();
arg->parent->sur_task->sut_port->sup_base->sup_vtable->
su_port_create();
if (task->sut_port) { if (task->sut_port) {
task->sut_port->sup_thread = 1; task->sut_port->sup_thread = 1;
...@@ -498,14 +496,14 @@ static void su_pthread_port_clone_break(su_root_magic_t *m, ...@@ -498,14 +496,14 @@ static void su_pthread_port_clone_break(su_root_magic_t *m,
*/ */
void su_pthread_port_wait(su_clone_r rclone) void su_pthread_port_wait(su_clone_r rclone)
{ {
su_port_t *parent, *clone; su_port_t *clone, *parent;
struct su_pthread_port_waiting_parent mom[1]; struct su_pthread_port_waiting_parent mom[1];
pthread_t tid; pthread_t tid;
parent = su_msg_from(rclone)->sut_port;
clone = su_msg_to(rclone)->sut_port; clone = su_msg_to(rclone)->sut_port;
parent = su_msg_from(rclone)->sut_port;
if (parent == clone) { if (clone == parent) {
su_base_port_wait(rclone); su_base_port_wait(rclone);
return; return;
} }
...@@ -541,9 +539,10 @@ void su_pthread_port_wait(su_clone_r rclone) ...@@ -541,9 +539,10 @@ void su_pthread_port_wait(su_clone_r rclone)
pthread_cond_wait(mom->cv, mom->mutex); pthread_cond_wait(mom->cv, mom->mutex);
/* Run all messages from clone */ /* Run all messages from clone */
su_base_port_getmsgs_from_port(parent, clone); while (su_port_getmsgs_from(parent, clone))
;
/* Wait for clone thread to exit */ /* Allow clone thread to exit */
pthread_mutex_unlock(mom->deinit); pthread_mutex_unlock(mom->deinit);
pthread_join(tid, NULL); pthread_join(tid, NULL);
......
...@@ -51,7 +51,6 @@ struct su_root_s; ...@@ -51,7 +51,6 @@ struct su_root_s;
#define SU_ROOT_MAGIC_T struct su_root_magic_s #define SU_ROOT_MAGIC_T struct su_root_magic_s
#define SU_WAKEUP_ARG_T struct su_wakeup_arg_s #define SU_WAKEUP_ARG_T struct su_wakeup_arg_s
#define SU_TIMER_ARG_T struct su_timer_arg_s #define SU_TIMER_ARG_T struct su_timer_arg_s
#define SU_CLONE_T su_msg_t
#include "su_port.h" #include "su_port.h"
#include "sofia-sip/su_alloc.h" #include "sofia-sip/su_alloc.h"
...@@ -350,49 +349,6 @@ int su_task_detach(su_task_r self); ...@@ -350,49 +349,6 @@ int su_task_detach(su_task_r self);
int su_timer_reset_all(su_timer_t **t0, su_task_r); int su_timer_reset_all(su_timer_t **t0, su_task_r);
/**@ingroup su_wait
*
* @page su_clone_t Clone Objects
*
* The process may be divided into many tasks via cloning. Several tasks may
* run in context of one thread, or each task may be run by its own thread.
* However, only a single thread can execute code within a task. There can
* be a 1-to-N mapping from thread to tasks. Thus, software using tasks can
* be executed by multiple threads in a multithreaded environment and by a
* single thread in a singlethreaded environment.
*
* The clones are useful for handling tasks that can be executed by a
* separate threads, but which do not block excessively. When threads are
* not available or they are not needed, clones can also be run in a
* single-threaded mode. Running in single-threaded mode is especially
* useful while debugging.
*
* A clone task is created with function su_clone_start(). Each clone has
* its own root object (su_root_t), which holds a context pointer
* (su_root_magic_t *). The context object can be different from that of
* parent task.
*
* When a clone is started, the clone initialization function is called. The
* initialization function should do whatever initialization there is to be
* performed, register I/O events and timers, and then return. If the
* initialization is successful, the clone task reverts to run the event
* loop and invoking the event callbacks until its parent stops it by
* calling su_clone_wait() which invokes the deinit function. The clone task
* is destroyed when the deinit function returns.
*
* The public API consists of following functions:
* - su_clone_start()
* - su_clone_task()
* - su_clone_wait()
* - su_clone_forget()
*
* @note
* There is only one event loop for each thread which can be shared by
* multiple clone tasks. Therefore, the clone tasks can not explicitly run
* or step the event loop, but they are limited to event callbacks. A clone
* task may not call su_root_break(), su_root_run() or su_root_step().
*/
/* Note that is *not* necessary same as su_root_t, /* Note that is *not* necessary same as su_root_t,
* as su_root_t can be extended */ * as su_root_t can be extended */
...@@ -857,200 +813,6 @@ int su_root_remove_prepoll(su_root_t *root) ...@@ -857,200 +813,6 @@ int su_root_remove_prepoll(su_root_t *root)
return su_port_remove_prepoll(root->sur_port, root); return su_port_remove_prepoll(root->sur_port, root);
} }
/* ========================================================================
* su_clone_t
*/
static int su_root_init_nothing(su_root_t *root, su_root_magic_t *magic)
{
return 0;
}
static void su_root_deinit_nothing(su_root_t *root, su_root_magic_t *magic)
{
}
/** Start a clone task.
*
* Allocate and initialize a sub-task. Depending on the su_root_threading()
* settings, a separate thread may be created to execute the sub-task. The
* sub-task is represented by clone handle to the rest of the application.
* The function su_clone_start() returns the clone handle in @a
* return_clone. The clone handle is used to communicate with the newly
* created clone task using messages.
*
* A new #su_root_t object is created for the sub-task with the @a magic as
* the root context pointer. Because the sub-task may or may not have its
* own thread, all its activity must be scheduled via this root object. In
* other words, the sub-task can be schedule
* -# I/O events with su_root_register()
* -# timers with su_timer_set(), su_timer_set_at() or su_timer_run()
* -# messages with su_msg_send().
*
* Messages can also be used to pass information between tasks or threads.
*
* In multi-threaded implementation, su_clone_start() launches a new thread,
* and the initialization routine is executed by this newly created thread.
* The calling thread blocks until the initialization routine completes. If
* the initialization routine returns #su_success (0), the sub-task is
* considered to be created successfully. After the successful
* initialization, the sub-task continues to execeute the function
* su_root_run().
*
* In single-threaded implementations, just a new root object is created.
* The initialization routine is called directly from su_clone_start().
*
* If the initalization function @a init fails, the sub-task (either the
* newly created thread or the current thread executing the su_clone_start()
* function) calls the deinitialization function, and su_clone_start()
* returns NULL.
*
* @param parent root to be cloned
* @param return_clone reference to a clone [OUT]
* @param magic pointer to user data
* @param init initialization function
* @param deinit deinitialization function
*
* @return 0 if successfull, -1 upon an error.
*
* @note Earlier documentation mentioned that @a parent could be NULL. That
* feature has never been implemented, however.
*
* @sa su_root_threading(), su_clone_task(), su_clone_stop(), su_clone_wait(),
* su_clone_forget().
*/
int su_clone_start(su_root_t *parent,
su_clone_r return_clone,
su_root_magic_t *magic,
su_root_init_f init,
su_root_deinit_f deinit)
{
if (parent == NULL)
return errno = EFAULT;
if (init == NULL)
init = su_root_init_nothing;
if (deinit == NULL)
deinit = su_root_deinit_nothing;
return su_port_start(parent, return_clone, magic, init, deinit);
}
/** Get reference to a clone task.
*
* @param clone Clone pointer
*
* @return A reference to the task structure of the clone.
*/
_su_task_r su_clone_task(su_clone_r clone)
{
return su_msg_to(clone);
}
/**Forget the clone.
*
* Normally, the clone task executes until it is stopped. If the parent
* task does not need to stop the task, it can "forget" the clone. The
* clone exits independently of the parent task.
*
* @param rclone Reference to the clone.
*/
void su_clone_forget(su_clone_r rclone)
{
su_msg_destroy(rclone);
}
/** Stop the clone.
*
* This can used only if clone task has sent no report messages (messages
* with delivery report sent back to clone).
*
* @deprecated. Use su_clone_wait().
*/
void su_clone_stop(su_clone_r rclone)
{
su_msg_send(rclone);
}
/** Stop a clone and wait until it is has completed.
*
* The function su_clone_wait() is used to stop the clone task and wait
* until it has cleaned up. The clone task is destroyed asynchronously. The
* parent sends a message to clone, clone deinitializes itself and then
* replies. After the reply message is received by the parent, it will send
* a third message back to clone.
*
* The parent destroy all messages to or from clone task before calling
* su_clone_wait(). The parent task may not send any messages to the clone
* after calling su_clone_wait(). The su_clone_wait() function blocks until
* the cloned task is destroyed. During that time, the parent task must be
* prepared to process all the messages sent by clone task. This includes
* all the messages sent by clone before destroy the message reached the
* clone.
*/
void su_clone_wait(su_root_t *root, su_clone_r rclone)
{
if (rclone[0]) {
assert(root == NULL || root == su_msg_from(rclone)->sut_root);
su_port_wait(rclone);
}
}
/** Pause a clone.
*
* Obtain an exclusive lock on clone's private data.
*
* @retval 0 if successful (and clone is paused)
* @retval -1 upon an error
*
* @deprecated Never implemented.
*/
int su_clone_pause(su_clone_r rclone)
{
#if 0
su_root_t *cloneroot = su_task_root(su_msg_to(rclone));
if (!cloneroot)
return (errno = EFAULT), -1;
if (SU_ROOT_OWN_THREAD(cloneroot))
/* We own it already */
return 0;
return su_port_pause(cloneroot->sur_port);
#else
return errno = ENOSYS, -1;
#endif
}
/** Resume a clone.