Difference between revisions of "User:Kr/A Thread's Life/Library Example with SAL"
m |
m |
||
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. | ||
Line 11: | Line 9: | ||
* Passing of the "oslThread" object to the worker function, otherwise it must be explicitly passed with help of conditions etc. | * Passing of the "oslThread" object to the worker function, otherwise it must be explicitly passed with help of conditions etc. | ||
* Better named "osl_scheduleThread". | * 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==== | ====How-to Build==== |
Revision as of 11:38, 31 October 2007
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
[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;
}
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
[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
The DEF File
HEAPSIZE 0 EXPORTS