Difference between revisions of "User:Kr/A Thread's Life/Library Example with SAL"
From Apache OpenOffice Wiki
< User:Kr | A Thread's Life
m |
(→Makefile: Adapted to <source> tag.) |
||
(8 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
SAL Thread Issues: | SAL Thread Issues: | ||
− | |||
− | |||
* Different semantic of UNIX and Win32 implementations | * Different semantic of UNIX and Win32 implementations | ||
* Problematic "pthread_detach" in UNIX usage, likely leading to races if trying to join a thread. | * 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. | * Problematic "CloseHandle" in Win32 usage, only easily possible to create "detached" (daemon) threads if calling "osl_destroyThread" from within the new thread. | ||
− | |||
RFE: | RFE: | ||
* Reliable thread cancellation mechanism ... | * 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==== | ||
+ | <pre> | ||
+ | Get an OOo build environment | ||
+ | mkdir salexample | ||
+ | mkdir salexample/source | ||
+ | mkdir salexample/prj | ||
+ | touch salexample/prj/d.lst | ||
+ | cd salexample/source | ||
+ | dmake | ||
+ | </pre> | ||
+ | |||
+ | ====The Program==== | ||
+ | <source lang="cpp"> | ||
+ | |||
+ | #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; | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | ====Library Header==== | ||
+ | <source lang="cpp">[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 | ||
+ | </source> | ||
+ | |||
+ | ====Library Implementation==== | ||
+ | <source lang="cpp">[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; | ||
+ | </source> | ||
+ | |||
+ | ====Makefile==== | ||
+ | <source lang="cpp"> | ||
+ | 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 | ||
+ | </source> | ||
+ | |||
+ | ====The DEF File==== | ||
+ | <pre> | ||
+ | HEAPSIZE 0 | ||
+ | EXPORTS | ||
+ | </pre> |
Latest revision as of 20:20, 10 June 2008
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"
Contents
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