Difference between revisions of "User:Kr/A Thread's Life"
From Apache OpenOffice Wiki
< User:Kr
m (Incorporated code review feedback.) |
m |
||
(7 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
− | Status: | + | Type: Proposal Status: Draft |
+ | Todos: | ||
+ | * Rework and aligned examples. | ||
+ | * Convert SAL examples to 'C' | ||
+ | * Bug examples for SAL threads. | ||
+ | * Issues for the bugs. | ||
==Two types of Threads== | ==Two types of Threads== | ||
Line 12: | Line 17: | ||
====Examples==== | ====Examples==== | ||
− | * | + | * A thread dispatching user interface events. |
+ | * A thread dispatching remote UNO messages. | ||
===Daemon=== | ===Daemon=== | ||
* Daemons don't keep the process alive. | * Daemons don't keep the process alive. | ||
− | * A daemon must be joinable, as | + | * A daemon must be joinable, as it is going to be joined during shutdown of the subsystem. |
− | * | + | * The termination of a daemon may be enforced by asking it for cancellation (pthread_cancel) or by killing (pthread_kill) it. |
====Sleepy Daemons==== | ====Sleepy Daemons==== | ||
− | Daemons waiting for an event (e.g. | + | Daemons waiting for an event (e.g. a condition) to do something, going to sleep afterwards again. |
====Short lived Daemons==== | ====Short lived Daemons==== | ||
− | Daemons doing something, terminating afterwards. | + | Daemons doing something asynchronously, terminating afterwards. |
====Examples==== | ====Examples==== | ||
− | * | + | * A thread flushing a cache every once a while. |
==Notes== | ==Notes== | ||
* Threads may dynamically switch from one type to the other and vice versa. | * Threads may dynamically switch from one type to the other and vice versa. | ||
− | * The "main" thread | + | * The "main" thread starts an activity. |
==Example== | ==Example== | ||
− | {{:User:Kr/A | + | ===Single Executable using pthreads=== |
+ | {{:User:Kr/A Thread's Life/Example Code}} | ||
+ | |||
+ | ===Executable and Library using pthreads=== | ||
+ | {{:User:Kr/A Thread's Life/Library Example}} | ||
+ | |||
+ | ===Executable and Library using SAL=== | ||
+ | {{:User:Kr/A Thread's Life/Library_Example_with_SAL}} | ||
+ | |||
[[Category:Multi-Threading]] | [[Category:Multi-Threading]] | ||
+ | [[Category:draft]] | ||
+ | [[Category:Proposal]] |
Latest revision as of 11:45, 31 October 2007
Type: Proposal Status: Draft
Todos:
- Rework and aligned examples.
- Convert SAL examples to 'C'
- Bug examples for SAL threads.
- Issues for the bugs.
Contents
Two types of Threads
- Active threads - activities
- Daemon threads - daemons (see wikipedia:Daemon (computer software))
Activity
- Activities keep the process alive.
- The last activity terminating leads to the termination of the entire process.
- An activity must be detached, as it is not going to be joined.
Examples
- A thread dispatching user interface events.
- A thread dispatching remote UNO messages.
Daemon
- Daemons don't keep the process alive.
- A daemon must be joinable, as it is going to be joined during shutdown of the subsystem.
- The termination of a daemon may be enforced by asking it for cancellation (pthread_cancel) or by killing (pthread_kill) it.
Sleepy Daemons
Daemons waiting for an event (e.g. a condition) to do something, going to sleep afterwards again.
Short lived Daemons
Daemons doing something asynchronously, terminating afterwards.
Examples
- A thread flushing a cache every once a while.
Notes
- Threads may dynamically switch from one type to the other and vice versa.
- The "main" thread starts an activity.
Example
Single Executable using pthreads
// // gcc -Wall -g example.c -o main.bin -lpthread // #include <stdlib.h> #include <stdio.h> #include <pthread.h> #include <string.h> #include <unistd.h> void my_pthread_cancel(pthread_t thread) { int res; if ((res = pthread_cancel(thread))) { fprintf(stderr, "%s(%p) => %s\n", __PRETTY_FUNCTION__, (void*)thread, strerror(res)); // There seems to be an issue on Linux with pthread_cancel, // returning an error in case "thread" has already terminated, // though not joined. // abort(); } } void my_pthread_join(pthread_t th, void **thread_return) { int res; if ((res = pthread_join(th, thread_return))) { fprintf(stderr, "%s - %s\n", __PRETTY_FUNCTION__, strerror(res)); abort(); } } typedef struct Daemon Daemon; struct Daemon { Daemon * previous_; Daemon * next_; void (*func_)(void); pthread_t hd_; int finished_; }; static pthread_mutex_t daemons_mutex_ = PTHREAD_MUTEX_INITIALIZER; static Daemon * firstDaemon_ = NULL; static unsigned int daemons_ = 0; static void daemons_join_(int finished) { pthread_mutex_lock(&daemons_mutex_); Daemon * daemon = firstDaemon_; while (daemon) { Daemon * next = daemon->next_; if (!finished || daemon->finished_) { -- daemons_; if (daemon->next_) daemon->next_->previous_ = daemon->previous_; if (daemon->previous_) daemon->previous_->next_ = daemon->next_; if (firstDaemon_ == daemon) firstDaemon_ = daemon->next_; pthread_mutex_unlock(&daemons_mutex_); my_pthread_join(daemon->hd_, NULL); pthread_mutex_lock(&daemons_mutex_); daemon->hd_ = 0xffffffff; free(daemon); daemon = firstDaemon_; } else daemon = next; } pthread_mutex_unlock(&daemons_mutex_); } /* Daemon finish function. */ static void daemon_finish(Daemon * daemon) { int oldstate; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); daemons_join_(1); pthread_mutex_lock(&daemons_mutex_); daemon->finished_ = 1; pthread_mutex_unlock(&daemons_mutex_); pthread_setcancelstate(oldstate, NULL); } static void * daemon_func(Daemon * daemon) { pthread_cleanup_push((void (*)(void *))daemon_finish, daemon); daemon->func_(); pthread_cleanup_pop(1); return NULL; } /* Create a "Daemon" struct and register it. Start the "Daemon". */ static void daemon_create_(void (*func)(void)) { Daemon * daemon = malloc(sizeof(Daemon)); daemon->func_ = func; daemon->finished_ = 0; pthread_mutex_lock(&daemons_mutex_); daemon->previous_ = NULL; daemon->next_ = firstDaemon_; if (firstDaemon_) firstDaemon_->previous_ = daemon; firstDaemon_ = daemon; ++ daemons_; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, 0); pthread_create(&daemon->hd_, NULL, (void *(*)(void *))daemon_func, daemon); pthread_attr_destroy(&attr); pthread_mutex_unlock(&daemons_mutex_); } /* Ask all registered daemons for cancellation and join them. */ static void daemons_cancelAndJoin_(void) { fprintf(stderr, "Joining daemons ... "); pthread_mutex_lock(&daemons_mutex_); Daemon * daemon = firstDaemon_; while (daemon) { my_pthread_cancel(daemon->hd_); // respectively //pthread_kill(); fprintf(stderr, "# "); daemon = daemon->next_; } pthread_mutex_unlock(&daemons_mutex_); daemons_join_(0); fprintf(stderr, "done\n"); } static unsigned int activities_ = 1; // The "main" thread is the first "activity". static pthread_mutex_t activity_mutex_ = PTHREAD_MUTEX_INITIALIZER; static void activity_terminate_(void) { int use_exit = 0; pthread_mutex_lock(&activity_mutex_); -- activities_; use_exit = activities_ == 0; pthread_mutex_unlock(&activity_mutex_); // Terminate the process, if this was the last "activity"! if (use_exit) exit(0); else pthread_exit(NULL); } static void * activity_func_(void (*func)(void)) { func(); activity_terminate_(); return NULL; } static void activity_create_(void (*func)(void)) { pthread_attr_t attr; /* Activities need to be detached. */ pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, 1); pthread_t bt; pthread_create(&bt, &attr, (void *(*)(void *))activity_func_, func); pthread_attr_destroy(&attr); pthread_mutex_lock(&activity_mutex_); ++ activities_; pthread_mutex_unlock(&activity_mutex_); } /* Some daemon functions. */ static void log_threads(void) { fprintf(stderr, "activities: %u daemons: %u\n", activities_, daemons_); } static void log_daemon_(void) { while (1) { log_threads(); sleep(1); /* This is a cancellation point. */ } } static void some_daemon_(void) { int n = 10; while (n) { sleep(1); if (rand() < (RAND_MAX / (daemons_ + 1))) daemon_create_(some_daemon_); -- n; } } /* Some activity functions. */ static void some_activity_(void) { int n = 3; while (n) { sleep(1); if (rand() < (RAND_MAX / (activities_ + 1))) activity_create_(some_activity_); if (rand() < (RAND_MAX / (daemons_ + 1))) daemon_create_(some_daemon_); -- n; } } static void main_activity_(void) { srand (time (0)); daemon_create_(log_daemon_); daemon_create_(some_daemon_); activity_create_(some_activity_); sleep(3); daemon_create_(some_daemon_); sleep(5); } int main(void) { atexit(log_threads); atexit(daemons_cancelAndJoin_); main_activity_(); activity_terminate_(); return 0; }
Executable and Library using pthreads
The Main Program
/* ** gcc -Wall -g main.c -o main.bin -lpthread -ldl */ #include "library.h" #include <stdlib.h> #include <stdio.h> #include <pthread.h> #include <string.h> #include <unistd.h> #include <dlfcn.h> static unsigned int activities_ = 1; /* The "main" thread is the first "activity". */ static pthread_mutex_t activity_mutex_ = PTHREAD_MUTEX_INITIALIZER; static void activity_terminate_(void) { int use_exit = 0; pthread_mutex_lock(&activity_mutex_); -- activities_; use_exit = activities_ == 0; pthread_mutex_unlock(&activity_mutex_); /* Terminate the process, if this was the last "activity"! */ if (use_exit) exit(0); else pthread_exit(NULL); } static void * activity_func_(void (*func)(void)) { func(); activity_terminate_(); return NULL; } static void activity_create_(void (*func)(void)) { pthread_attr_t attr; /* Activities need to be detached. */ pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, 1); pthread_t bt; pthread_create(&bt, &attr, (void *(*)(void *))activity_func_, func); pthread_attr_destroy(&attr); pthread_mutex_lock(&activity_mutex_); ++ activities_; pthread_mutex_unlock(&activity_mutex_); } /* Some daemon functions. */ static daemon_create_t * pdaemon_create_; static daemons_getCount_t * pdaemons_getCount_; static void log_threads(void) { fprintf(stderr, "activities: %u daemons: %u\n", activities_, pdaemons_getCount_ ? pdaemons_getCount_() : 0); } static void log_daemon_(void) { while (1) { log_threads(); /* This is a cancellation point. */ sleep(1); } } static void some_daemon_(void) { int n = 10; while (n) { sleep(1); if (rand() < (RAND_MAX / (pdaemons_getCount_() + 1))) pdaemon_create_(some_daemon_); -- n; } } /* Some activity functions. */ static void some_activity_(void) { int n = 3; while (n) { sleep(1); if (rand() < (RAND_MAX / (activities_ + 1))) activity_create_(some_activity_); if (rand() < (RAND_MAX / (pdaemons_getCount_() + 1))) pdaemon_create_(some_daemon_); -- n; } } static void main_activity_(void) { srand(time (0)); pdaemon_create_(log_daemon_); pdaemon_create_(some_daemon_); activity_create_(some_activity_); sleep(3); pdaemon_create_(some_daemon_); sleep(5); } static void * dlhd_ = NULL; static void close_library(void) { daemons_cancelAndJoin_t * pdaemons_cancelAndJoin = dlsym(dlhd_, "daemons_cancelAndJoin"); if (pdaemons_cancelAndJoin) pdaemons_cancelAndJoin(); dlclose(dlhd_); pdaemon_create_ = NULL; pdaemons_getCount_ = NULL; } int main(void) { atexit(log_threads); atexit(close_library); dlhd_ = dlopen("library.so", RTLD_NOW); pdaemon_create_ = dlsym(dlhd_, "daemon_create"); pdaemons_getCount_ = dlsym(dlhd_, "daemons_getCount"); main_activity_(); activity_terminate_(); return 0; } </code> ====Library Header==== <code>[cpp] #ifndef library_h_included # define library_h_included typedef void daemon_create_t (void (*func)(void)); typedef int daemons_getCount_t (void); typedef void daemons_cancelAndJoin_t(void); void daemon_create (void (*func)(void)); int daemons_getCount (void); void daemons_cancelAndJoin(void); #endif </code> ====Library Implementation==== <code>[cpp] /* ** gcc -Wall -g library.c -shared -o library.so -lpthread */ #include "library.h" #include <stdlib.h> #include <stdio.h> #include <pthread.h> #include <string.h> #include <unistd.h> static void my_pthread_cancel(pthread_t thread) { int res; if ((res = pthread_cancel(thread))) { fprintf(stderr, "%s(%p) => %s\n", __PRETTY_FUNCTION__, (void*)thread, strerror(res)); /* There seems to be an issue on Linux with pthread_cancel, ** returning an error in case "thread" has already terminated, ** though not joined. */ /* abort(); */ } } static void my_pthread_join(pthread_t th, void **thread_return) { int res; if ((res = pthread_join(th, thread_return))) { fprintf(stderr, "%s - %s\n", __PRETTY_FUNCTION__, strerror(res)); abort(); } } typedef struct Daemon Daemon; struct Daemon { Daemon * previous_; Daemon * next_; void (*func_)(void); pthread_t hd_; int finished_; }; static pthread_mutex_t daemons_mutex_ = PTHREAD_MUTEX_INITIALIZER; static Daemon * firstDaemon_ = NULL; static unsigned int daemons_ = 0; int daemons_getCount(void) { return daemons_; } /* Joins all or only "finished" daemons. */ static void daemons_join_(int finished) { pthread_mutex_lock(&daemons_mutex_); Daemon * daemon = firstDaemon_; while (daemon) { Daemon * next = daemon->next_; if (!finished || daemon->finished_) { -- daemons_; if (daemon->next_) daemon->next_->previous_ = daemon->previous_; if (daemon->previous_) daemon->previous_->next_ = daemon->next_; if (firstDaemon_ == daemon) firstDaemon_ = daemon->next_; pthread_mutex_unlock(&daemons_mutex_); my_pthread_join(daemon->hd_, NULL); pthread_mutex_lock(&daemons_mutex_); daemon->hd_ = 0xffffffff; free(daemon); daemon = firstDaemon_; } else daemon = next; } pthread_mutex_unlock(&daemons_mutex_); } /* Daemon finish function. */ static void daemon_finish_(Daemon * daemon) { int oldstate; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); daemons_join_(1); pthread_mutex_lock(&daemons_mutex_); daemon->finished_ = 1; pthread_mutex_unlock(&daemons_mutex_); pthread_setcancelstate(oldstate, NULL); } static void * daemon_func_(Daemon * daemon) { pthread_cleanup_push((void (*)(void *))daemon_finish_, daemon); daemon->func_(); pthread_cleanup_pop(1); return NULL; } /* Create a "Daemon" struct and register it. Start the "Daemon". */ void daemon_create(void (*func)(void)) { Daemon * daemon = malloc(sizeof(Daemon)); daemon->func_ = func; daemon->finished_ = 0; pthread_mutex_lock(&daemons_mutex_); daemon->previous_ = NULL; daemon->next_ = firstDaemon_; if (firstDaemon_) firstDaemon_->previous_ = daemon; firstDaemon_ = daemon; ++ daemons_; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, 0); pthread_create(&daemon->hd_, NULL, (void *(*)(void *))daemon_func_, daemon); pthread_attr_destroy(&attr); pthread_mutex_unlock(&daemons_mutex_); } /* Ask all registered daemons for cancellation and join them. */ /* Calling pthread_canel from within _fini leads to deadlocks.*/ /* static void __attribute__((destructor)) daemons_cancelAndJoin_(void) {*/ void daemons_cancelAndJoin(void) { fprintf(stderr, "Cancelling daemons ... "); pthread_mutex_lock(&daemons_mutex_); Daemon * daemon = firstDaemon_; while (daemon) { my_pthread_cancel(daemon->hd_); /* respectively */ /*pthread_kill();*/ fprintf(stderr, "# "); daemon = daemon->next_; } pthread_mutex_unlock(&daemons_mutex_); fprintf(stderr, "done\n"); fprintf(stderr, "Joining daemons ... "); daemons_join_(0); fprintf(stderr, "done\n"); }
Executable and Library using SAL
SAL Thread Issues:
- Different semantic of UNIX and Win32 implementations
- Problematic "pthread_detach" in UNIX usage, likely leading to races if trying to join a thread.
- Problematic "CloseHandle" in Win32 usage, only easily possible to create "detached" (daemon) threads if calling "osl_destroyThread" from within the new thread.
RFE:
- Reliable thread cancellation mechanism ...
- Result setting function. Needed in multi-thread keeping process alive scenario.
- Passing of the "oslThread" object to the worker function, otherwise it must be explicitly passed with help of conditions etc.
- Better named "osl_scheduleThread".
- A way to get this threads "oslThread".
- Missing pendant to "pthread_exit" / "ExitThread" and therefore also missing clean-up handlers etc.
- Less capable cancellation mechanism compared to "pthread_cancel"
How-to Build
Get an OOo build environment mkdir salexample mkdir salexample/source mkdir salexample/prj touch salexample/prj/d.lst cd salexample/source dmake
The Program
#include "library.hxx" #include <sal/main.h> #include <osl/interlck.h> #include <osl/thread.h> #include <osl/module.hxx> #include <rtl/alloc.h> #include <stdio.h> #include <time.h> #ifdef WNT extern "C" void _endthread(void); #else # include <pthread.h> #endif static oslInterlockedCount activities_ = 1; /* The "main" thread is the first "activity". */ static void activity_terminate_(void) { int use_exit = 0; use_exit = osl_decrementInterlockedCount(&activities_) == 0; /* Terminate the process, if this was the last "activity"! */ if (use_exit) exit(0); else #ifdef WNT _endthread(); #else pthread_exit(NULL); #endif } typedef void activity_worker_t(void); static void activity_func_(activity_worker_t ** ffunc) { activity_worker_t * func = *ffunc; rtl_freeMemory(ffunc); func(); activity_terminate_(); } static void activity_create_(activity_worker_t * func) { activity_worker_t ** ffunc = (activity_worker_t **)rtl_allocateMemory(sizeof(activity_worker_t *)); *ffunc = func; oslThread thread = osl_createThread((oslWorkerFunction)activity_func_, ffunc); /* Activities need to be detached. */ #ifndef UNX TimeValue oneSecond_ = {1, 0}; osl_waitThread(&oneSecond_); osl_destroyThread(thread); #else (void)thread; #endif osl_incrementInterlockedCount(&activities_); } /* Some daemon functions. */ static daemon_create_t * pdaemon_create_; static daemons_getCount_t * pdaemons_getCount_; extern "C" void log_threads(void) { fprintf(stderr, "activities: %u daemons: %u\n", activities_, pdaemons_getCount_ ? pdaemons_getCount_() : 0); } static TimeValue oneSecond_ = {1, 0}; static void log_daemon_(oslThread thread) { fprintf(stderr, "\tlog daemon starting ...\n"); while (osl_scheduleThread(thread)) { log_threads(); osl_waitThread(&oneSecond_); } fprintf(stderr, "\tlog daemon finishing ...\n"); } static void some_daemon_(oslThread thread) /*throw (int)*/ { fprintf(stderr, "\tsome daemon starting ...\n"); int n = 10; while (osl_scheduleThread(thread) && n > 0) { osl_waitThread(&oneSecond_); if (rand() < (RAND_MAX / (pdaemons_getCount_() + 1))) pdaemon_create_(some_daemon_, thread); -- n; } fprintf(stderr, "\tsome daemon finishing ...\n"); } /* Some activity functions. */ static void some_activity_(void) { fprintf(stderr, "\tsome activitiy starting ...\n"); srand(time (0)); int n = 3; while (n) { osl_waitThread(&oneSecond_); if (rand() < (RAND_MAX / (activities_ + 1))) activity_create_(some_activity_); if (rand() < (RAND_MAX / (pdaemons_getCount_() + 1))) pdaemon_create_(some_daemon_, NULL); -- n; } fprintf(stderr, "\tsome activitiy dying ...\n"); } static osl::Module library; #if defined GCC # define DAEMON_CREATE "_Z13daemon_createPFvPvES_" # define DAEMONS_GETCOUNT "_Z16daemons_getCountv" # define DAEMONS_CANCELANDJOIN "_Z21daemons_cancelAndJoinv" #elif defined __SUNPRO_CC # define DAEMON_CREATE "__1cNdaemon_create6FpFpv_v0_v_" # define DAEMONS_GETCOUNT "__1cQdaemons_getCount6F_i_" # define DAEMONS_CANCELANDJOIN "__1cVdaemons_cancelAndJoin6F_v_" #elif defined _MSC_VER # define DAEMON_CREATE "?daemon_create@@YAXP6AXPAX@Z0@Z" # define DAEMONS_GETCOUNT "?daemons_getCount@@YAHXZ" # define DAEMONS_CANCELANDJOIN "?daemons_cancelAndJoin@@YAXXZ" #else # error "unknown compiler" #endif extern "C" void close_library(void) { daemons_cancelAndJoin_t * pdaemons_cancelAndJoin = (daemons_cancelAndJoin_t *)library.getFunctionSymbol(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(DAEMONS_CANCELANDJOIN))); pdaemons_cancelAndJoin(); library.unload(); pdaemon_create_ = NULL; pdaemons_getCount_ = NULL; } SAL_IMPLEMENT_MAIN() { atexit(log_threads); atexit(close_library); library.load(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("library" SAL_DLLEXTENSION))); pdaemon_create_ = (daemon_create_t *)library.getFunctionSymbol( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(DAEMON_CREATE))); pdaemons_getCount_ = (daemons_getCount_t *)library.getFunctionSymbol( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(DAEMONS_GETCOUNT))); pdaemon_create_(log_daemon_, NULL); some_activity_(); activity_terminate_(); return 0; }
Library Header
[cpp] #ifndef library_hxx_included # define library_hxx_included #include <osl/thread.h> #ifdef LIBRARY_IMPL # define LIBRARY_EXPORT SAL_DLLPUBLIC_EXPORT #else # define LIBRARY_EXPORT SAL_DLLPUBLIC_IMPORT #endif typedef void daemon_worker_t(oslThread thread); typedef void daemon_create_t (daemon_worker_t * func, oslThread thread); typedef int daemons_getCount_t (void); typedef void daemons_cancelAndJoin_t(void); LIBRARY_EXPORT void daemon_create (daemon_worker_t * func, oslThread thread) /*throw (int)*/; LIBRARY_EXPORT int daemons_getCount (void); LIBRARY_EXPORT void daemons_cancelAndJoin(void); #endif
Library Implementation
[cpp] #define LIBRARY_IMPL #include "library.hxx" #include <rtl/alloc.h> #include <osl/mutex.h> #include <osl/thread.h> #include <stdio.h> typedef struct Daemon Daemon; struct Daemon { Daemon * previous_; Daemon * next_; daemon_worker_t * func_; oslThread hd_; int finished_; }; static oslMutex daemons_mutex_; struct DaemonConstruct { DaemonConstruct() { daemons_mutex_ = osl_createMutex(); } ~DaemonConstruct() { osl_destroyMutex(daemons_mutex_); } }; static DaemonConstruct daemonConstruct; static Daemon * firstDaemon_ = NULL; static unsigned int daemons_ = 0; int daemons_getCount(void) { return daemons_; } /* Joins all or only "finished" daemons. */ static void daemons_join_(int finished) { osl_acquireMutex(daemons_mutex_); Daemon * daemon = firstDaemon_; while (daemon) { Daemon * next = daemon->next_; if (!finished || daemon->finished_) { -- daemons_; if (daemon->next_) daemon->next_->previous_ = daemon->previous_; if (daemon->previous_) daemon->previous_->next_ = daemon->next_; if (firstDaemon_ == daemon) firstDaemon_ = daemon->next_; osl_releaseMutex(daemons_mutex_); osl_joinWithThread(daemon->hd_); osl_acquireMutex(daemons_mutex_); osl_destroyThread(daemon->hd_); rtl_freeMemory(daemon); daemon = firstDaemon_; } else daemon = next; } osl_releaseMutex(daemons_mutex_); } /* Daemon finish function. */ static void daemon_finish_(Daemon * daemon) { daemons_join_(1); osl_acquireMutex(daemons_mutex_); daemon->finished_ = 1; osl_releaseMutex(daemons_mutex_); } static void daemon_func_(Daemon * daemon) { try { daemon->func_(daemon->hd_); } catch (...) { fprintf(stderr, " caught something ...\n"); } daemon_finish_(daemon); } /* Create a "Daemon" struct and register it. Start the "Daemon". */ LIBRARY_EXPORT void daemon_create(daemon_worker_t * func, oslThread thread) /*throw (int)*/ { Daemon * daemon = (Daemon *)rtl_allocateMemory(sizeof(Daemon)); daemon->func_ = func; daemon->finished_ = 0; osl_acquireMutex(daemons_mutex_); // add a cancelation point if (thread && !osl_scheduleThread(thread)) { osl_releaseMutex(daemons_mutex_); rtl_freeMemory(daemon); throw int(); } daemon->previous_ = NULL; daemon->next_ = firstDaemon_; if (firstDaemon_) firstDaemon_->previous_ = daemon; firstDaemon_ = daemon; ++ daemons_; daemon->hd_ = osl_createSuspendedThread((oslWorkerFunction)daemon_func_, daemon); osl_resumeThread(daemon->hd_); osl_releaseMutex(daemons_mutex_); } /* Ask all registered daemons for cancellation and join them. */ /* Calling pthread_canel from within _fini leads to deadlocks.*/ /* static void __attribute__((destructor)) daemons_cancelAndJoin_(void) {*/ void daemons_cancelAndJoin(void) { fprintf(stderr, "Cancelling daemons ... "); osl_acquireMutex(daemons_mutex_); Daemon * daemon = firstDaemon_; while (daemon) { osl_terminateThread(daemon->hd_); /* respectively "osl_killThread" :-) */ fprintf(stderr, "# "); daemon = daemon->next_; } osl_releaseMutex(daemons_mutex_); fprintf(stderr, "done\n"); fprintf(stderr, "Joining daemons ... "); daemons_join_(0); fprintf(stderr, "done\n"); } struct LibExit { LibExit() { fprintf(stderr, "initializing library ...\n"); } ~LibExit() { fprintf(stderr, "de-initializing library ...\n"); // daemons_cancelAndJoin(); } }; static LibExit libExit;
Makefile
PRJ := .. PRJNAME := SALTHREADS TARGET := main USE_DEFFILE := TRUE ENABLE_EXCEPTIONS := TRUE .INCLUDE : settings.mk .IF "$(OS)"=="SOLARIS" DIRECT := .ENDIF APP1TARGET := main APP1OBJS := $(OBJ)$/main.obj .IF "$(OS)"=="SOLARIS" APP1STDLIBS := -lrary $(SALLIB) .ELSE APP1STDLIBS := $(SALLIB) .ENDIF SHL1DLLPRE := SHL1TARGET := library SHL1OBJS := $(SLO)$/library.obj SHL1STDLIBS := $(SALHELPERLIB) $(SALLIB) #SHL1IMPLIB := i$(SHL1TARGET) SHL1DEF := empty.def .INCLUDE : target.mk
The DEF File
HEAPSIZE 0 EXPORTS