summaryrefslogtreecommitdiff
path: root/omnithread
diff options
context:
space:
mode:
authoreb2007-01-30 02:12:05 +0000
committereb2007-01-30 02:12:05 +0000
commit6ff1faed9d4c7095ab2d07b99478fe46e35f0e1e (patch)
tree033696613d2bd899d9e8178827d2bc0aad609771 /omnithread
parentb8a177591928973eb863cc3690fb381306830bbd (diff)
downloadgnuradio-6ff1faed9d4c7095ab2d07b99478fe46e35f0e1e.tar.gz
gnuradio-6ff1faed9d4c7095ab2d07b99478fe46e35f0e1e.tar.bz2
gnuradio-6ff1faed9d4c7095ab2d07b99478fe46e35f0e1e.zip
Merged eb/omni -r4315:4327 into trunk.
Extracted omnithread from gnuradio-core and made it a top-level component. This allows mblock to use it without a dependency on gnuradio-core. Completes ticket:132 git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@4328 221aa14e-8319-0410-a670-987f0aec2ac5
Diffstat (limited to 'omnithread')
-rw-r--r--omnithread/Makefile.am68
-rw-r--r--omnithread/dir.mk229
-rw-r--r--omnithread/mach.cc714
-rw-r--r--omnithread/nt.cc969
-rw-r--r--omnithread/omnithread.h622
-rw-r--r--omnithread/ot_VxThread.h118
-rw-r--r--omnithread/ot_mach.h51
-rw-r--r--omnithread/ot_nt.h85
-rw-r--r--omnithread/ot_posix.h81
-rw-r--r--omnithread/ot_pthread_nt.h186
-rw-r--r--omnithread/ot_solaris.h47
-rw-r--r--omnithread/posix.cc972
-rw-r--r--omnithread/solaris.cc615
-rw-r--r--omnithread/threaddata.cc83
-rw-r--r--omnithread/vxWorks.cc1160
15 files changed, 6000 insertions, 0 deletions
diff --git a/omnithread/Makefile.am b/omnithread/Makefile.am
new file mode 100644
index 000000000..2eac4c920
--- /dev/null
+++ b/omnithread/Makefile.am
@@ -0,0 +1,68 @@
+#
+# Copyright 2003 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+include $(top_srcdir)/Makefile.common
+
+# This is the omnithread package,
+# extracted from the omniORB-4.0.1 distribution
+
+# we should do some configure hacking to determine these on the fly
+OMNITHREAD_DEFINES = -DPthreadDraftVersion=10
+
+INCLUDES = $(DEFINES) $(OMNITHREAD_DEFINES) $(OMNITHREAD_INCLUDES)
+
+# we call it libgromnithread to avoid a collision with libomnithread on Debian
+lib_LTLIBRARIES = libgromnithread.la
+
+# At this point we only support the posix and nt pthreads i/f...
+
+if OMNITHREAD_POSIX
+libgromnithread_la_SOURCES = \
+ posix.cc
+endif
+
+if OMNITHREAD_NT
+libgromnithread_la_SOURCES = \
+ nt.cc
+endif
+
+libgromnithread_la_LIBADD = \
+ $(PTHREAD_LIBS)
+
+# ... but this code also came with the package
+
+EXTRA_DIST = \
+ mach.cc \
+ nt.cc \
+ posix.cc \
+ solaris.cc \
+ threaddata.cc \
+ vxWorks.cc \
+ dir.mk
+
+grinclude_HEADERS = \
+ omnithread.h \
+ ot_mach.h \
+ ot_nt.h \
+ ot_posix.h \
+ ot_pthread_nt.h \
+ ot_solaris.h \
+ ot_VxThread.h
diff --git a/omnithread/dir.mk b/omnithread/dir.mk
new file mode 100644
index 000000000..d53803417
--- /dev/null
+++ b/omnithread/dir.mk
@@ -0,0 +1,229 @@
+ifeq ($(ThreadSystem),Solaris)
+CXXSRCS = solaris.cc
+DIR_CPPFLAGS = $(OMNITHREAD_CPPFLAGS)
+endif
+
+ifeq ($(ThreadSystem),Posix)
+CXXSRCS = posix.cc
+DIR_CPPFLAGS = $(OMNITHREAD_CPPFLAGS) $(OMNITHREAD_POSIX_CPPFLAGS)
+endif
+
+ifeq ($(ThreadSystem),NT)
+CXXSRCS = nt.cc
+DIR_CPPFLAGS = $(OMNITHREAD_CPPFLAGS)
+MSVC_STATICLIB_CXXNODEBUGFLAGS += -D_WINSTATIC
+MSVC_STATICLIB_CXXDEBUGFLAGS += -D_WINSTATIC
+MSVC_DLL_CXXNODEBUGFLAGS += -D_OMNITHREAD_DLL
+MSVC_DLL_CXXDEBUGFLAGS += -D_OMNITHREAD_DLL
+endif
+
+ifeq ($(ThreadSystem),NTPosix)
+CXXSRCS = posix.cc
+DIR_CPPFLAGS = $(OMNITHREAD_CPPFLAGS)
+MSVC_STATICLIB_CXXNODEBUGFLAGS += -D_WINSTATIC
+MSVC_STATICLIB_CXXDEBUGFLAGS += -D_WINSTATIC
+MSVC_DLL_CXXNODEBUGFLAGS += -D_OMNITHREAD_DLL
+MSVC_DLL_CXXDEBUGFLAGS += -D_OMNITHREAD_DLL
+endif
+
+ifeq ($(ThreadSystem),Mach)
+CXXSRCS = mach.cc
+DIR_CPPFLAGS = $(OMNITHREAD_CPPFLAGS)
+endif
+
+ifeq ($(ThreadSystem),vxWorks)
+CXXSRCS = vxWorks.cc
+OBJS = vxWorks.o
+DIR_CPPFLAGS = $(OMNITHREAD_CPPFLAGS)
+endif
+
+LIB_NAME := omnithread
+LIB_VERSION := $(OMNITHREAD_VERSION)
+LIB_OBJS := $(CXXSRCS:.cc=.o)
+LIB_IMPORTS := $(OMNITHREAD_PLATFORM_LIB)
+
+all:: mkstatic mkshared
+
+export:: mkstatic mkshared
+
+ifdef INSTALLTARGET
+install:: mkstatic mkshared
+endif
+
+vers := $(subst ., ,$(LIB_VERSION))
+ifeq ($(words $(vers)), 2)
+ vers := _ $(vers)
+ major := ""
+else
+ major := $(word 1, $(vers))
+endif
+
+namespec := $(LIB_NAME) $(vers)
+
+##############################################################################
+# Build Static library
+##############################################################################
+
+ifndef NoStaticLibrary
+
+staticlib := static/$(patsubst %,$(LibNoDebugPattern),$(LIB_NAME)$(major))
+
+mkstatic::
+ @(dir=static; $(CreateDir))
+
+mkstatic:: $(staticlib)
+
+$(staticlib): $(patsubst %, static/%, $(LIB_OBJS))
+ @$(StaticLinkLibrary)
+
+export:: $(staticlib)
+ @$(ExportLibrary)
+
+ifdef INSTALLTARGET
+install:: $(staticlib)
+ @$(InstallLibrary)
+endif
+
+clean::
+ $(RM) static/*.o
+ $(RM) $(staticlib)
+
+veryclean::
+ $(RM) static/*.o
+ $(RM) $(staticlib)
+
+else
+
+mkstatic::
+
+endif
+
+
+##############################################################################
+# Build Shared library
+##############################################################################
+ifdef BuildSharedLibrary
+
+shlib := shared/$(shell $(SharedLibraryFullName) $(namespec))
+
+ifdef Win32Platform
+# in case of Win32 lossage:
+ imps := $(patsubst $(DLLDebugSearchPattern),$(DLLNoDebugSearchPattern), \
+ $(LIB_IMPORTS))
+else
+ imps := $(LIB_IMPORTS)
+endif
+
+mkshared::
+ @(dir=shared; $(CreateDir))
+
+mkshared:: $(shlib)
+
+$(shlib): $(patsubst %, shared/%, $(LIB_OBJS))
+ @(namespec="$(namespec)" extralibs="$(imps)" nodeffile=1; \
+ $(MakeCXXSharedLibrary))
+
+export:: $(shlib)
+ @(namespec="$(namespec)"; \
+ $(ExportSharedLibrary))
+
+ifdef INSTALLTARGET
+install:: $(shlib)
+ @(namespec="$(namespec)"; \
+ $(InstallSharedLibrary))
+endif
+
+clean::
+ $(RM) shared/*.o
+ (dir=shared; $(CleanSharedLibrary))
+
+veryclean::
+ $(RM) shared/*.o
+ @(dir=shared; $(CleanSharedLibrary))
+
+else
+
+mkshared::
+
+endif
+
+##############################################################################
+# Build debug libraries for Win32
+##############################################################################
+ifdef Win32Platform
+
+ifdef BuildSharedLibrary
+
+all:: mkstaticdbug mkshareddbug
+
+export:: mkstaticdbug mkshareddbug
+
+else
+
+all:: mkstaticdbug
+
+export:: mkstaticdbug
+
+endif
+
+
+#####################################################
+# Static debug libraries
+#####################################################
+
+dbuglib := debug/$(patsubst %,$(LibDebugPattern),$(LIB_NAME)$(major))
+
+mkstaticdbug::
+ @(dir=debug; $(CreateDir))
+
+mkstaticdbug:: $(dbuglib)
+
+$(dbuglib): $(patsubst %, debug/%, $(LIB_OBJS))
+ @$(StaticLinkLibrary)
+
+export:: $(dbuglib)
+ @$(ExportLibrary)
+
+clean::
+ $(RM) debug/*.o
+ $(RM) $(dbuglib)
+
+veryclean::
+ $(RM) debug/*.o
+ $(RM) $(dbuglib)
+
+#####################################################
+# DLL debug libraries
+#####################################################
+
+ifdef BuildSharedLibrary
+
+dbugshlib := shareddebug/$(shell $(SharedLibraryDebugFullName) $(namespec))
+
+dbugimps := $(patsubst $(DLLNoDebugSearchPattern),$(DLLDebugSearchPattern), \
+ $(LIB_IMPORTS))
+
+mkshareddbug::
+ @(dir=shareddebug; $(CreateDir))
+
+mkshareddbug:: $(dbugshlib)
+
+$(dbugshlib): $(patsubst %, shareddebug/%, $(LIB_OBJS))
+ (namespec="$(namespec)" debug=1 extralibs="$(dbugimps)" nodeffile=1; \
+ $(MakeCXXSharedLibrary))
+
+export:: $(dbugshlib)
+ @(namespec="$(namespec)" debug=1; \
+ $(ExportSharedLibrary))
+
+clean::
+ $(RM) shareddebug/*.o
+ @(dir=shareddebug; $(CleanSharedLibrary))
+
+veryclean::
+ $(RM) shareddebug/*.o
+ @(dir=shareddebug; $(CleanSharedLibrary))
+
+endif
+endif
+
diff --git a/omnithread/mach.cc b/omnithread/mach.cc
new file mode 100644
index 000000000..8759bb4ce
--- /dev/null
+++ b/omnithread/mach.cc
@@ -0,0 +1,714 @@
+// Package : omnithread
+// omnithread/mach.cc Created : 7/97 lars immisch lars@ibp.de
+//
+// Copyright (C) 1997 Immisch, Becker & Partner
+//
+// This file is part of the omnithread library
+//
+// The omnithread library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free
+// Software Foundation, Inc., 51 Franklin Street, Boston, MA
+// 02110-1301, USA
+//
+
+//
+// Implementation of OMNI thread abstraction for mach threads
+//
+// to the author's pleasure, mach cthreads are very similar to posix threads
+//
+
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <mach/cthreads.h>
+#include "omnithread.h"
+
+#define DB(x) // x
+// #include <iostream> or #include <iostream.h> if DB is on.
+
+#define ERRNO(x) (x)
+
+//
+// static variables
+//
+
+int omni_thread::init_t::count = 0;
+
+omni_mutex* omni_thread::next_id_mutex;
+int omni_thread::next_id = 0;
+
+static int normal_priority;
+static int highest_priority;
+
+static size_t stack_size = 0;
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Mutex
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+omni_mutex::omni_mutex(void)
+{
+ mutex_init(&mach_mutex);
+}
+
+
+omni_mutex::~omni_mutex(void)
+{
+ mutex_clear(&mach_mutex);
+}
+
+
+void omni_mutex::lock(void)
+{
+ mutex_lock(&mach_mutex);
+}
+
+
+void omni_mutex::unlock(void)
+{
+ mutex_unlock(&mach_mutex);
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Condition variable
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+omni_condition::omni_condition(omni_mutex* m) : mutex(m)
+{
+ condition_init(&mach_cond);
+}
+
+
+omni_condition::~omni_condition(void)
+{
+ condition_clear(&mach_cond);
+}
+
+void
+omni_condition::wait(void)
+{
+ condition_wait(&mach_cond, &mutex->mach_mutex);
+}
+
+typedef struct alarmclock_args {
+ unsigned long secs;
+ unsigned long nsecs;
+ bool wakeup;
+ condition_t condition;
+ mutex_t mutex;
+};
+
+any_t alarmclock(any_t arg)
+{
+ alarmclock_args* alarm = (alarmclock_args*)arg;
+
+ omni_thread::sleep(alarm->secs, alarm->nsecs);
+
+ mutex_lock(alarm->mutex);
+
+ alarm->wakeup = TRUE;
+
+ condition_signal(alarm->condition);
+
+ mutex_unlock(alarm->mutex);
+
+ return (any_t)TRUE;
+}
+
+int omni_condition::timedwait(unsigned long abs_secs, unsigned long abs_nsecs)
+{
+ alarmclock_args alarm;
+
+ omni_thread::get_time(&alarm.secs, &alarm.nsecs, 0, 0);
+
+ if (abs_secs < alarm.secs || (abs_secs == alarm.secs && abs_nsecs <= alarm.nsecs))
+ return ETIMEDOUT;
+
+ alarm.secs = abs_secs - alarm.secs;
+ if (abs_nsecs <= alarm.nsecs) {
+ alarm.nsecs = 1000000 - alarm.nsecs + abs_nsecs;
+ alarm.secs--;
+ }
+ else {
+ alarm.nsecs = abs_nsecs - alarm.nsecs;
+ }
+
+ alarm.mutex = &mutex->mach_mutex;
+ alarm.condition = &mach_cond;
+ alarm.wakeup = FALSE;
+
+ cthread_t ct = cthread_fork((cthread_fn_t)alarmclock, (any_t)&alarm);
+ cthread_detach(ct);
+
+ condition_wait(&mach_cond, &mutex->mach_mutex);
+
+ if (alarm.wakeup) {
+ return 0;
+ }
+
+ // interrupt the alarmclock thread sleep
+ cthread_abort(ct);
+
+ // wait until it has signalled the condition
+ condition_wait(&mach_cond, &mutex->mach_mutex);
+
+ return 1;
+}
+
+
+void omni_condition::signal(void)
+{
+ condition_signal(&mach_cond);
+}
+
+
+void omni_condition::broadcast(void)
+{
+ condition_signal(&mach_cond);
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Counting semaphore
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+omni_semaphore::omni_semaphore(unsigned int initial) : c(&m)
+{
+ value = initial;
+}
+
+
+omni_semaphore::~omni_semaphore(void)
+{
+}
+
+
+void
+omni_semaphore::wait(void)
+{
+ omni_mutex_lock l(m);
+
+ while (value == 0)
+ c.wait();
+
+ value--;
+}
+
+
+int
+omni_semaphore::trywait(void)
+{
+ omni_mutex_lock l(m);
+
+ if (value == 0)
+ return 0;
+
+ value--;
+ return 1;
+}
+
+
+void
+omni_semaphore::post(void)
+{
+ omni_mutex_lock l(m);
+
+ if (value == 0)
+ c.signal();
+
+ value++;
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Thread
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+
+//
+// Initialisation function (gets called before any user code).
+//
+
+omni_thread::init_t::init_t(void)
+{
+ if (count++ != 0) // only do it once however many objects get created.
+ return;
+
+ //
+ // find base and max priority.
+ // This is the initial thread, so the max priority of this
+ // thread also applies to any newly created thread.
+ //
+
+ kern_return_t error;
+ struct thread_sched_info info;
+ unsigned int info_count = THREAD_SCHED_INFO_COUNT;
+
+ error = thread_info(thread_self(), THREAD_SCHED_INFO, (thread_info_t)&info, &info_count);
+ if (error != KERN_SUCCESS) {
+ DB(cerr << "omni_thread::init: error determining thread_info" << endl);
+ ::exit(1);
+ }
+ else {
+ normal_priority = info.base_priority;
+ highest_priority = info.max_priority;
+ }
+
+ next_id_mutex = new omni_mutex;
+
+ //
+ // Create object for this (i.e. initial) thread.
+ //
+
+ omni_thread* t = new omni_thread;
+
+ if (t->_state != STATE_NEW) {
+ DB(cerr << "omni_thread::init: problem creating initial thread object\n");
+ ::exit(1);
+ }
+
+ t->_state = STATE_RUNNING;
+
+ t->mach_thread = cthread_self();
+
+ DB(cerr << "initial thread " << t->id() << endl);
+
+ cthread_set_data(t->mach_thread, (any_t)t);
+}
+
+
+//
+// Wrapper for thread creation.
+//
+
+extern "C" void*
+omni_thread_wrapper(void* ptr)
+{
+ omni_thread* me = (omni_thread*)ptr;
+
+ DB(cerr << "omni_thread::wrapper: thread " << me->id()
+ << " started\n");
+
+ cthread_set_data(cthread_self(), (any_t)me);
+
+ //
+ // Now invoke the thread function with the given argument.
+ //
+
+ if (me->fn_void != NULL) {
+ (*me->fn_void)(me->thread_arg);
+ omni_thread::exit();
+ }
+
+ if (me->fn_ret != NULL) {
+ void* return_value = (*me->fn_ret)(me->thread_arg);
+ omni_thread::exit(return_value);
+ }
+
+ if (me->detached) {
+ me->run(me->thread_arg);
+ omni_thread::exit();
+ } else {
+ void* return_value = me->run_undetached(me->thread_arg);
+ omni_thread::exit(return_value);
+ }
+
+ // should never get here.
+
+ return NULL;
+}
+
+
+//
+// Constructors for omni_thread - set up the thread object but don't
+// start it running.
+//
+
+// construct a detached thread running a given function.
+
+omni_thread::omni_thread(void (*fn)(void*), void* arg, priority_t pri)
+{
+ common_constructor(arg, pri, 1);
+ fn_void = fn;
+ fn_ret = NULL;
+}
+
+// construct an undetached thread running a given function.
+
+omni_thread::omni_thread(void* (*fn)(void*), void* arg, priority_t pri)
+{
+ common_constructor(arg, pri, 0);
+ fn_void = NULL;
+ fn_ret = fn;
+}
+
+// construct a thread which will run either run() or run_undetached().
+
+omni_thread::omni_thread(void* arg, priority_t pri)
+{
+ common_constructor(arg, pri, 1);
+ fn_void = NULL;
+ fn_ret = NULL;
+}
+
+// common part of all constructors.
+
+void omni_thread::common_constructor(void* arg, priority_t pri, int det)
+{
+ _state = STATE_NEW;
+ _priority = pri;
+
+ next_id_mutex->lock();
+ _id = next_id++;
+ next_id_mutex->unlock();
+
+ thread_arg = arg;
+ detached = det; // may be altered in start_undetached()
+
+ _dummy = 0;
+ _values = 0;
+ _value_alloc = 0;
+ // posix_thread is set up in initialisation routine or start().
+}
+
+
+//
+// Destructor for omni_thread.
+//
+
+omni_thread::~omni_thread(void)
+{
+ DB(cerr << "destructor called for thread " << id() << endl);
+ if (_values) {
+ for (key_t i=0; i < _value_alloc; i++) {
+ if (_values[i]) {
+ delete _values[i];
+ }
+ }
+ delete [] _values;
+ }
+}
+
+
+//
+// Start the thread
+//
+
+void
+omni_thread::start(void)
+{
+ omni_mutex_lock l(mutex);
+
+ int rc;
+
+ if (_state != STATE_NEW)
+ throw omni_thread_invalid();
+
+ mach_thread = cthread_fork(omni_thread_wrapper, (any_t)this);
+
+ _state = STATE_RUNNING;
+
+ if (detached) {
+ cthread_detach(mach_thread);
+ }
+}
+
+//
+// Start a thread which will run the member function run_undetached().
+//
+
+void
+omni_thread::start_undetached(void)
+{
+ if ((fn_void != NULL) || (fn_ret != NULL))
+ throw omni_thread_invalid();
+
+ detached = 0;
+ start();
+}
+
+
+//
+// join - simply check error conditions & call cthread_join.
+//
+
+void
+omni_thread::join(void** status)
+{
+ mutex.lock();
+
+ if ((_state != STATE_RUNNING) && (_state != STATE_TERMINATED)) {
+ mutex.unlock();
+ throw omni_thread_invalid();
+ }
+
+ mutex.unlock();
+
+ if (this == self())
+ throw omni_thread_invalid();
+
+ if (detached)
+ throw omni_thread_invalid();
+
+ DB(cerr << "omni_thread::join: doing cthread_join\n");
+
+ *status = cthread_join(mach_thread);
+
+ delete this;
+}
+
+
+//
+// Change this thread's priority.
+//
+
+void
+omni_thread::set_priority(priority_t pri)
+{
+ omni_mutex_lock l(mutex);
+
+ if (_state != STATE_RUNNING)
+ throw omni_thread_invalid();
+
+ _priority = pri;
+
+ kern_return_t rc = cthread_priority(mach_thread, mach_priority(pri), FALSE);
+
+ if (rc != KERN_SUCCESS)
+ throw omni_thread_fatal(errno);
+}
+
+//
+// create - construct a new thread object and start it running. Returns thread
+// object if successful, null pointer if not.
+//
+
+// detached version
+
+omni_thread*
+omni_thread::create(void (*fn)(void*), void* arg, priority_t pri)
+{
+ omni_thread* t = new omni_thread(fn, arg, pri);
+
+ t->start();
+
+ return t;
+}
+
+// undetached version
+
+omni_thread*
+omni_thread::create(void* (*fn)(void*), void* arg, priority_t pri)
+{
+ omni_thread* t = new omni_thread(fn, arg, pri);
+
+ t->start();
+
+ return t;
+}
+
+//
+// exit() _must_ lock the mutex even in the case of a detached thread. This is
+// because a thread may run to completion before the thread that created it has
+// had a chance to get out of start(). By locking the mutex we ensure that the
+// creating thread must have reached the end of start() before we delete the
+// thread object. Of course, once the call to start() returns, the user can
+// still incorrectly refer to the thread object, but that's their problem.
+//
+
+void omni_thread::exit(void* return_value)
+{
+ omni_thread* me = self();
+
+ if (me)
+ {
+ me->mutex.lock();
+
+ if (me->_state != STATE_RUNNING)
+ DB(cerr << "omni_thread::exit: thread not in \"running\" state\n");
+
+ me->_state = STATE_TERMINATED;
+
+ me->mutex.unlock();
+
+ DB(cerr << "omni_thread::exit: thread " << me->id() << " detached "
+ << me->detached << " return value " << return_value << endl);
+
+ if (me->detached)
+ delete me;
+ }
+ else
+ {
+ DB(cerr << "omni_thread::exit: called with a non-omnithread. Exit quietly." << endl);
+ }
+ cthread_exit(return_value);
+}
+
+omni_thread* omni_thread::self(void)
+{
+ omni_thread* me;
+
+ me = (omni_thread*)cthread_data(cthread_self());
+
+ if (!me) {
+ // This thread is not created by omni_thread::start because it
+ // doesn't has a class omni_thread instance attached to its key.
+ DB(cerr << "omni_thread::self: called with a non-ominthread. NULL is returned." << endl);
+ }
+
+ return me;
+}
+
+void omni_thread::yield(void)
+{
+ cthread_yield();
+}
+
+#define MAX_SLEEP_SECONDS (unsigned)4294966 // (2**32-2)/1000
+
+void
+omni_thread::sleep(unsigned long secs, unsigned long nanosecs)
+{
+ if (secs <= MAX_SLEEP_SECONDS) {
+ thread_switch(THREAD_NULL, SWITCH_OPTION_WAIT, secs * 1000 + nanosecs / 1000000);
+ return;
+ }
+
+ unsigned no_of_max_sleeps = secs / MAX_SLEEP_SECONDS;
+
+ for (unsigned i = 0; i < no_of_max_sleeps; i++)
+ thread_switch(THREAD_NULL, SWITCH_OPTION_WAIT, MAX_SLEEP_SECONDS * 1000);
+
+ thread_switch(THREAD_NULL, SWITCH_OPTION_WAIT,
+ (secs % MAX_SLEEP_SECONDS) * 1000 + nanosecs / 1000000);
+
+ return;
+}
+
+void
+omni_thread::get_time(unsigned long* abs_sec, unsigned long* abs_nsec,
+ unsigned long rel_sec, unsigned long rel_nsec)
+{
+ int rc;
+ unsigned long tv_sec;
+ unsigned long tv_nsec;
+ struct timeval tv;
+
+ rc = gettimeofday(&tv, NULL);
+ if (rc) throw omni_thread_fatal(rc);
+
+ tv_sec = tv.tv_sec;
+ tv_nsec = tv.tv_usec * 1000;
+
+ tv_nsec += rel_nsec;
+ tv_sec += rel_sec + tv_nsec / 1000000000;
+ tv_nsec = tv_nsec % 1000000000;
+
+ *abs_sec = tv_sec;
+ *abs_nsec = tv_nsec;
+}
+
+
+int
+omni_thread::mach_priority(priority_t pri)
+{
+ switch (pri) {
+
+ case PRIORITY_LOW:
+ return 0;
+
+ case PRIORITY_NORMAL:
+ return normal_priority;
+
+ case PRIORITY_HIGH:
+ return highest_priority;
+
+ default:
+ return -1;
+ }
+}
+
+void
+omni_thread::stacksize(unsigned long sz)
+{
+ stack_size = sz;
+}
+
+unsigned long
+omni_thread::stacksize()
+{
+ return stack_size;
+}
+
+
+//
+// Dummy thread
+//
+
+#error This dummy thread code is not tested. It might work if you're lucky.
+
+class omni_thread_dummy : public omni_thread {
+public:
+ inline omni_thread_dummy() : omni_thread()
+ {
+ _dummy = 1;
+ _state = STATE_RUNNING;
+ mach_thread = cthread_self();
+ cthread_set_data(mach_thread, (any_t)this));
+ }
+ inline ~omni_thread_dummy()
+ {
+ cthread_set_data(mach_thread, (any_t)0));
+ }
+};
+
+omni_thread*
+omni_thread::create_dummy()
+{
+ if (omni_thread::self())
+ throw omni_thread_invalid();
+
+ return new omni_thread_dummy;
+}
+
+void
+omni_thread::release_dummy()
+{
+ omni_thread* self = omni_thread::self();
+ if (!self || !self->_dummy)
+ throw omni_thread_invalid();
+
+ omni_thread_dummy* dummy = (omni_thread_dummy*)self;
+ delete dummy;
+}
+
+
+#define INSIDE_THREAD_IMPL_CC
+#include "threaddata.cc"
+#undef INSIDE_THREAD_IMPL_CC
diff --git a/omnithread/nt.cc b/omnithread/nt.cc
new file mode 100644
index 000000000..3853f0108
--- /dev/null
+++ b/omnithread/nt.cc
@@ -0,0 +1,969 @@
+// Package : omnithread
+// omnithread/nt.cc Created : 6/95 tjr
+//
+// Copyright (C) 2006 Free Software Foundation, Inc.
+// Copyright (C) 1995-1999 AT&T Laboratories Cambridge
+//
+// This file is part of the omnithread library
+//
+// The omnithread library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free
+// Software Foundation, Inc., 51 Franklin Street, Boston, MA
+// 02110-1301, USA
+//
+
+//
+// Implementation of OMNI thread abstraction for NT threads
+//
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <errno.h>
+#include <WinError.h>
+#include <omnithread.h>
+#include <process.h>
+
+#define DB(x) // x
+//#include <iostream.h> or #include <iostream> if DB is on.
+
+static void get_time_now(unsigned long* abs_sec, unsigned long* abs_nsec);
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Mutex
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+omni_mutex::omni_mutex(void)
+{
+ InitializeCriticalSection(&crit);
+}
+
+omni_mutex::~omni_mutex(void)
+{
+ DeleteCriticalSection(&crit);
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Condition variable
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+//
+// Condition variables are tricky to implement using NT synchronisation
+// primitives, since none of them have the atomic "release mutex and wait to be
+// signalled" which is central to the idea of a condition variable. To get
+// around this the solution is to record which threads are waiting and
+// explicitly wake up those threads.
+//
+// Here we implement a condition variable using a list of waiting threads
+// (protected by a critical section), and a per-thread semaphore (which
+// actually only needs to be a binary semaphore).
+//
+// To wait on the cv, a thread puts itself on the list of waiting threads for
+// that cv, then releases the mutex and waits on its own personal semaphore. A
+// signalling thread simply takes a thread from the head of the list and kicks
+// that thread's semaphore. Broadcast is simply implemented by kicking the
+// semaphore of each waiting thread.
+//
+// The only other tricky part comes when a thread gets a timeout from a timed
+// wait on its semaphore. Between returning with a timeout from the wait and
+// entering the critical section, a signalling thread could get in, kick the
+// waiting thread's semaphore and remove it from the list. If this happens,
+// the waiting thread's semaphore is now out of step so it needs resetting, and
+// the thread should indicate that it was signalled rather than that it timed
+// out.
+//
+// It is possible that the thread calling wait or timedwait is not a
+// omni_thread. In this case we have to provide a temporary data structure,
+// i.e. for the duration of the call, for the thread to link itself on the
+// list of waiting threads. _internal_omni_thread_dummy provides such
+// a data structure and _internal_omni_thread_helper is a helper class to
+// deal with this special case for wait() and timedwait(). Once created,
+// the _internal_omni_thread_dummy is cached for use by the next wait() or
+// timedwait() call from a non-omni_thread. This is probably worth doing
+// because creating a Semaphore is quite heavy weight.
+
+class _internal_omni_thread_helper;
+
+class _internal_omni_thread_dummy : public omni_thread {
+public:
+ inline _internal_omni_thread_dummy() : next(0) { }
+ inline ~_internal_omni_thread_dummy() { }
+ friend class _internal_omni_thread_helper;
+private:
+ _internal_omni_thread_dummy* next;
+};
+
+class _internal_omni_thread_helper {
+public:
+ inline _internal_omni_thread_helper() {
+ d = 0;
+ t = omni_thread::self();
+ if (!t) {
+ omni_mutex_lock sync(cachelock);
+ if (cache) {
+ d = cache;
+ cache = cache->next;
+ }
+ else {
+ d = new _internal_omni_thread_dummy;
+ }
+ t = d;
+ }
+ }
+ inline ~_internal_omni_thread_helper() {
+ if (d) {
+ omni_mutex_lock sync(cachelock);
+ d->next = cache;
+ cache = d;
+ }
+ }
+ inline operator omni_thread* () { return t; }
+ inline omni_thread* operator->() { return t; }
+
+ static _internal_omni_thread_dummy* cache;
+ static omni_mutex cachelock;
+
+private:
+ _internal_omni_thread_dummy* d;
+ omni_thread* t;
+};
+
+_internal_omni_thread_dummy* _internal_omni_thread_helper::cache = 0;
+omni_mutex _internal_omni_thread_helper::cachelock;
+
+
+omni_condition::omni_condition(omni_mutex* m) : mutex(m)
+{
+ InitializeCriticalSection(&crit);
+ waiting_head = waiting_tail = NULL;
+}
+
+
+omni_condition::~omni_condition(void)
+{
+ DeleteCriticalSection(&crit);
+ DB( if (waiting_head != NULL) {
+ cerr << "omni_condition::~omni_condition: list of waiting threads "
+ << "is not empty\n";
+ } )
+}
+
+
+void
+omni_condition::wait(void)
+{
+ _internal_omni_thread_helper me;
+
+ EnterCriticalSection(&crit);
+
+ me->cond_next = NULL;
+ me->cond_prev = waiting_tail;
+ if (waiting_head == NULL)
+ waiting_head = me;
+ else
+ waiting_tail->cond_next = me;
+ waiting_tail = me;
+ me->cond_waiting = TRUE;
+
+ LeaveCriticalSection(&crit);
+
+ mutex->unlock();
+
+ DWORD result = WaitForSingleObject(me->cond_semaphore, INFINITE);
+
+ mutex->lock();
+
+ if (result != WAIT_OBJECT_0)
+ throw omni_thread_fatal(GetLastError());
+}
+
+
+int
+omni_condition::timedwait(unsigned long abs_sec, unsigned long abs_nsec)
+{
+ _internal_omni_thread_helper me;
+
+ EnterCriticalSection(&crit);
+
+ me->cond_next = NULL;
+ me->cond_prev = waiting_tail;
+ if (waiting_head == NULL)
+ waiting_head = me;
+ else
+ waiting_tail->cond_next = me;
+ waiting_tail = me;
+ me->cond_waiting = TRUE;
+
+ LeaveCriticalSection(&crit);
+
+ mutex->unlock();
+
+ unsigned long now_sec, now_nsec;
+
+ get_time_now(&now_sec, &now_nsec);
+
+ DWORD timeout;
+ if ((abs_sec <= now_sec) && ((abs_sec < now_sec) || (abs_nsec < now_nsec)))
+ timeout = 0;
+ else {
+ timeout = (abs_sec-now_sec) * 1000;
+
+ if( abs_nsec < now_nsec ) timeout -= (now_nsec-abs_nsec) / 1000000;
+ else timeout += (abs_nsec-now_nsec) / 1000000;
+ }
+
+ DWORD result = WaitForSingleObject(me->cond_semaphore, timeout);
+
+ if (result == WAIT_TIMEOUT) {
+ EnterCriticalSection(&crit);
+
+ if (me->cond_waiting) {
+ if (me->cond_prev != NULL)
+ me->cond_prev->cond_next = me->cond_next;
+ else
+ waiting_head = me->cond_next;
+ if (me->cond_next != NULL)
+ me->cond_next->cond_prev = me->cond_prev;
+ else
+ waiting_tail = me->cond_prev;
+ me->cond_waiting = FALSE;
+
+ LeaveCriticalSection(&crit);
+
+ mutex->lock();
+ return 0;
+ }
+
+ //
+ // We timed out but another thread still signalled us. Wait for
+ // the semaphore (it _must_ have been signalled) to decrement it
+ // again. Return that we were signalled, not that we timed out.
+ //
+
+ LeaveCriticalSection(&crit);
+
+ result = WaitForSingleObject(me->cond_semaphore, INFINITE);
+ }
+
+ if (result != WAIT_OBJECT_0)
+ throw omni_thread_fatal(GetLastError());
+
+ mutex->lock();
+ return 1;
+}
+
+
+void
+omni_condition::signal(void)
+{
+ EnterCriticalSection(&crit);
+
+ if (waiting_head != NULL) {
+ omni_thread* t = waiting_head;
+ waiting_head = t->cond_next;
+ if (waiting_head == NULL)
+ waiting_tail = NULL;
+ else
+ waiting_head->cond_prev = NULL;
+ t->cond_waiting = FALSE;
+
+ if (!ReleaseSemaphore(t->cond_semaphore, 1, NULL)) {
+ int rc = GetLastError();
+ LeaveCriticalSection(&crit);
+ throw omni_thread_fatal(rc);
+ }
+ }
+
+ LeaveCriticalSection(&crit);
+}
+
+
+void
+omni_condition::broadcast(void)
+{
+ EnterCriticalSection(&crit);
+
+ while (waiting_head != NULL) {
+ omni_thread* t = waiting_head;
+ waiting_head = t->cond_next;
+ if (waiting_head == NULL)
+ waiting_tail = NULL;
+ else
+ waiting_head->cond_prev = NULL;
+ t->cond_waiting = FALSE;
+
+ if (!ReleaseSemaphore(t->cond_semaphore, 1, NULL)) {
+ int rc = GetLastError();
+ LeaveCriticalSection(&crit);
+ throw omni_thread_fatal(rc);
+ }
+ }
+
+ LeaveCriticalSection(&crit);
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Counting semaphore
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+#define SEMAPHORE_MAX 0x7fffffff
+
+
+omni_semaphore::omni_semaphore(unsigned int initial, unsigned int max_count)
+{
+ if (max_count > SEMAPHORE_MAX)
+ max_count= SEMAPHORE_MAX;
+
+ nt_sem = CreateSemaphore(NULL, initial, max_count, NULL);
+
+ if (nt_sem == NULL) {
+ DB( cerr << "omni_semaphore::omni_semaphore: CreateSemaphore error "
+ << GetLastError() << endl );
+ throw omni_thread_fatal(GetLastError());
+ }
+}
+
+
+omni_semaphore::~omni_semaphore(void)
+{
+ if (!CloseHandle(nt_sem)) {
+ DB( cerr << "omni_semaphore::~omni_semaphore: CloseHandle error "
+ << GetLastError() << endl );
+ throw omni_thread_fatal(GetLastError());
+ }
+}
+
+
+void
+omni_semaphore::wait(void)
+{
+ if (WaitForSingleObject(nt_sem, INFINITE) != WAIT_OBJECT_0)
+ throw omni_thread_fatal(GetLastError());
+}
+
+
+int
+omni_semaphore::trywait(void)
+{
+ switch (WaitForSingleObject(nt_sem, 0)) {
+
+ case WAIT_OBJECT_0:
+ return 1;
+ case WAIT_TIMEOUT:
+ return 0;
+ }
+
+ throw omni_thread_fatal(GetLastError());
+ return 0; /* keep msvc++ happy */
+}
+
+
+void
+omni_semaphore::post(void)
+{
+ if (!ReleaseSemaphore(nt_sem, 1, NULL)
+ && GetLastError() != ERROR_TOO_MANY_POSTS ) // MinGW fix--see ticket:95 in trac
+ throw omni_thread_fatal(GetLastError());
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Thread
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+//
+// Static variables
+//
+
+omni_mutex* omni_thread::next_id_mutex;
+int omni_thread::next_id = 0;
+static DWORD self_tls_index;
+
+static unsigned int stack_size = 0;
+
+//
+// Initialisation function (gets called before any user code).
+//
+
+static int& count() {
+ static int the_count = 0;
+ return the_count;
+}
+
+omni_thread::init_t::init_t(void)
+{
+ if (count()++ != 0) // only do it once however many objects get created.
+ return;
+
+ DB(cerr << "omni_thread::init: NT implementation initialising\n");
+
+ self_tls_index = TlsAlloc();
+
+ if (self_tls_index == 0xffffffff)
+ throw omni_thread_fatal(GetLastError());
+
+ next_id_mutex = new omni_mutex;
+
+ //
+ // Create object for this (i.e. initial) thread.
+ //
+
+ omni_thread* t = new omni_thread;
+
+ t->_state = STATE_RUNNING;
+
+ if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
+ GetCurrentProcess(), &t->handle,
+ 0, FALSE, DUPLICATE_SAME_ACCESS))
+ throw omni_thread_fatal(GetLastError());
+
+ t->nt_id = GetCurrentThreadId();
+
+ DB(cerr << "initial thread " << t->id() << " NT thread id " << t->nt_id
+ << endl);
+
+ if (!TlsSetValue(self_tls_index, (LPVOID)t))
+ throw omni_thread_fatal(GetLastError());
+
+ if (!SetThreadPriority(t->handle, nt_priority(PRIORITY_NORMAL)))
+ throw omni_thread_fatal(GetLastError());
+}
+
+omni_thread::init_t::~init_t(void)
+{
+ if (--count() != 0) return;
+
+ omni_thread* self = omni_thread::self();
+ if (!self) return;
+
+ TlsSetValue(self_tls_index, (LPVOID)0);
+ delete self;
+
+ delete next_id_mutex;
+
+ TlsFree(self_tls_index);
+}
+
+//
+// Wrapper for thread creation.
+//
+
+extern "C"
+#ifndef __BCPLUSPLUS__
+unsigned __stdcall
+#else
+void _USERENTRY
+#endif
+omni_thread_wrapper(void* ptr)
+{
+ omni_thread* me = (omni_thread*)ptr;
+
+ DB(cerr << "omni_thread_wrapper: thread " << me->id()
+ << " started\n");
+
+ if (!TlsSetValue(self_tls_index, (LPVOID)me))
+ throw omni_thread_fatal(GetLastError());
+
+ //
+ // Now invoke the thread function with the given argument.
+ //
+
+ if (me->fn_void != NULL) {
+ (*me->fn_void)(me->thread_arg);
+ omni_thread::exit();
+ }
+
+ if (me->fn_ret != NULL) {
+ void* return_value = (*me->fn_ret)(me->thread_arg);
+ omni_thread::exit(return_value);
+ }
+
+ if (me->detached) {
+ me->run(me->thread_arg);
+ omni_thread::exit();
+ } else {
+ void* return_value = me->run_undetached(me->thread_arg);
+ omni_thread::exit(return_value);
+ }
+
+ // should never get here.
+#ifndef __BCPLUSPLUS__
+ return 0;
+#endif
+}
+
+
+//
+// Constructors for omni_thread - set up the thread object but don't
+// start it running.
+//
+
+// construct a detached thread running a given function.
+
+omni_thread::omni_thread(void (*fn)(void*), void* arg, priority_t pri)
+{
+ common_constructor(arg, pri, 1);
+ fn_void = fn;
+ fn_ret = NULL;
+}
+
+// construct an undetached thread running a given function.
+
+omni_thread::omni_thread(void* (*fn)(void*), void* arg, priority_t pri)
+{
+ common_constructor(arg, pri, 0);
+ fn_void = NULL;
+ fn_ret = fn;
+}
+
+// construct a thread which will run either run() or run_undetached().
+
+omni_thread::omni_thread(void* arg, priority_t pri)
+{
+ common_constructor(arg, pri, 1);
+ fn_void = NULL;
+ fn_ret = NULL;
+}
+
+// common part of all constructors.
+
+void
+omni_thread::common_constructor(void* arg, priority_t pri, int det)
+{
+ _state = STATE_NEW;
+ _priority = pri;
+
+ next_id_mutex->lock();
+ _id = next_id++;
+ next_id_mutex->unlock();
+
+ thread_arg = arg;
+ detached = det; // may be altered in start_undetached()
+
+ cond_semaphore = CreateSemaphore(NULL, 0, SEMAPHORE_MAX, NULL);
+
+ if (cond_semaphore == NULL)
+ throw omni_thread_fatal(GetLastError());
+
+ cond_next = cond_prev = NULL;
+ cond_waiting = FALSE;
+
+ handle = NULL;
+
+ _dummy = 0;
+ _values = 0;
+ _value_alloc = 0;
+}
+
+
+//
+// Destructor for omni_thread.
+//
+
+omni_thread::~omni_thread(void)
+{
+ DB(cerr << "destructor called for thread " << id() << endl);
+ if (_values) {
+ for (key_t i=0; i < _value_alloc; i++) {
+ if (_values[i]) {
+ delete _values[i];
+ }
+ }
+ delete [] _values;
+ }
+ if (handle && !CloseHandle(handle))
+ throw omni_thread_fatal(GetLastError());
+ if (cond_semaphore && !CloseHandle(cond_semaphore))
+ throw omni_thread_fatal(GetLastError());
+}
+
+
+//
+// Start the thread
+//
+
+void
+omni_thread::start(void)
+{
+ omni_mutex_lock l(mutex);
+
+ if (_state != STATE_NEW)
+ throw omni_thread_invalid();
+
+#ifndef __BCPLUSPLUS__
+ // MSVC++ or compatiable
+ unsigned int t;
+ handle = (HANDLE)_beginthreadex(
+ NULL,
+ stack_size,
+ omni_thread_wrapper,
+ (LPVOID)this,
+ CREATE_SUSPENDED,
+ &t);
+ nt_id = t;
+ if (handle == NULL)
+ throw omni_thread_fatal(GetLastError());
+#else
+ // Borland C++
+ handle = (HANDLE)_beginthreadNT(omni_thread_wrapper,
+ stack_size,
+ (void*)this,
+ NULL,
+ CREATE_SUSPENDED,
+ &nt_id);
+ if (handle == INVALID_HANDLE_VALUE)
+ throw omni_thread_fatal(errno);
+#endif
+
+ if (!SetThreadPriority(handle, nt_priority(_priority)))
+ throw omni_thread_fatal(GetLastError());
+
+ if (ResumeThread(handle) == 0xffffffff)
+ throw omni_thread_fatal(GetLastError());
+
+ _state = STATE_RUNNING;
+}
+
+
+//
+// Start a thread which will run the member function run_undetached().
+//
+
+void
+omni_thread::start_undetached(void)
+{
+ if ((fn_void != NULL) || (fn_ret != NULL))
+ throw omni_thread_invalid();
+
+ detached = 0;
+ start();
+}
+
+
+//
+// join - simply check error conditions & call WaitForSingleObject.
+//
+
+void
+omni_thread::join(void** status)
+{
+ mutex.lock();
+
+ if ((_state != STATE_RUNNING) && (_state != STATE_TERMINATED)) {
+ mutex.unlock();
+ throw omni_thread_invalid();
+ }
+
+ mutex.unlock();
+
+ if (this == self())
+ throw omni_thread_invalid();
+
+ if (detached)
+ throw omni_thread_invalid();
+
+ DB(cerr << "omni_thread::join: doing WaitForSingleObject\n");
+
+ if (WaitForSingleObject(handle, INFINITE) != WAIT_OBJECT_0)
+ throw omni_thread_fatal(GetLastError());
+
+ DB(cerr << "omni_thread::join: WaitForSingleObject succeeded\n");
+
+ if (status)
+ *status = return_val;
+
+ delete this;
+}
+
+
+//
+// Change this thread's priority.
+//
+
+void
+omni_thread::set_priority(priority_t pri)
+{
+ omni_mutex_lock l(mutex);
+
+ if (_state != STATE_RUNNING)
+ throw omni_thread_invalid();
+
+ _priority = pri;
+
+ if (!SetThreadPriority(handle, nt_priority(pri)))
+ throw omni_thread_fatal(GetLastError());
+}
+
+
+//
+// create - construct a new thread object and start it running. Returns thread
+// object if successful, null pointer if not.
+//
+
+// detached version
+
+omni_thread*
+omni_thread::create(void (*fn)(void*), void* arg, priority_t pri)
+{
+ omni_thread* t = new omni_thread(fn, arg, pri);
+ t->start();
+ return t;
+}
+
+// undetached version
+
+omni_thread*
+omni_thread::create(void* (*fn)(void*), void* arg, priority_t pri)
+{
+ omni_thread* t = new omni_thread(fn, arg, pri);
+ t->start();
+ return t;
+}
+
+
+//
+// exit() _must_ lock the mutex even in the case of a detached thread. This is
+// because a thread may run to completion before the thread that created it has
+// had a chance to get out of start(). By locking the mutex we ensure that the
+// creating thread must have reached the end of start() before we delete the
+// thread object. Of course, once the call to start() returns, the user can
+// still incorrectly refer to the thread object, but that's their problem.
+//
+
+void
+omni_thread::exit(void* return_value)
+{
+ omni_thread* me = self();
+
+ if (me)
+ {
+ me->mutex.lock();
+
+ me->_state = STATE_TERMINATED;
+
+ me->mutex.unlock();
+
+ DB(cerr << "omni_thread::exit: thread " << me->id() << " detached "
+ << me->detached << " return value " << return_value << endl);
+
+ if (me->detached) {
+ delete me;
+ } else {
+ me->return_val = return_value;
+ }
+ }
+ else
+ {
+ DB(cerr << "omni_thread::exit: called with a non-omnithread. Exit quietly." << endl);
+ }
+#ifndef __BCPLUSPLUS__
+ // MSVC++ or compatiable
+ // _endthreadex() does not automatically closes the thread handle.
+ // The omni_thread dtor closes the thread handle.
+ _endthreadex(0);
+#else
+ // Borland C++
+ // _endthread() does not automatically closes the thread handle.
+ // _endthreadex() is only available if __MFC_COMPAT__ is defined and
+ // all it does is to call _endthread().
+ _endthread();
+#endif
+}
+
+
+omni_thread*
+omni_thread::self(void)
+{
+ LPVOID me;
+
+ me = TlsGetValue(self_tls_index);
+
+ if (me == NULL) {
+ DB(cerr << "omni_thread::self: called with a non-ominthread. NULL is returned." << endl);
+ }
+ return (omni_thread*)me;
+}
+
+
+void
+omni_thread::yield(void)
+{
+ Sleep(0);
+}
+
+
+#define MAX_SLEEP_SECONDS (DWORD)4294966 // (2**32-2)/1000
+
+void
+omni_thread::sleep(unsigned long secs, unsigned long nanosecs)
+{
+ if (secs <= MAX_SLEEP_SECONDS) {
+ Sleep(secs * 1000 + nanosecs / 1000000);
+ return;
+ }
+
+ DWORD no_of_max_sleeps = secs / MAX_SLEEP_SECONDS;
+
+ for (DWORD i = 0; i < no_of_max_sleeps; i++)
+ Sleep(MAX_SLEEP_SECONDS * 1000);
+
+ Sleep((secs % MAX_SLEEP_SECONDS) * 1000 + nanosecs / 1000000);
+}
+
+
+void
+omni_thread::get_time(unsigned long* abs_sec, unsigned long* abs_nsec,
+ unsigned long rel_sec, unsigned long rel_nsec)
+{
+ get_time_now(abs_sec, abs_nsec);
+ *abs_nsec += rel_nsec;
+ *abs_sec += rel_sec + *abs_nsec / 1000000000;
+ *abs_nsec = *abs_nsec % 1000000000;
+}
+
+
+int
+omni_thread::nt_priority(priority_t pri)
+{
+ switch (pri) {
+
+ case PRIORITY_LOW:
+ return THREAD_PRIORITY_LOWEST;
+
+ case PRIORITY_NORMAL:
+ return THREAD_PRIORITY_NORMAL;
+
+ case PRIORITY_HIGH:
+ return THREAD_PRIORITY_HIGHEST;
+ }
+
+ throw omni_thread_invalid();
+ return 0; /* keep msvc++ happy */
+}
+
+
+static void
+get_time_now(unsigned long* abs_sec, unsigned long* abs_nsec)
+{
+ static int days_in_preceding_months[12]
+ = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+ static int days_in_preceding_months_leap[12]
+ = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
+
+ SYSTEMTIME st;
+
+ GetSystemTime(&st);
+ *abs_nsec = st.wMilliseconds * 1000000;
+
+ // this formula should work until 1st March 2100
+
+ DWORD days = ((st.wYear - 1970) * 365 + (st.wYear - 1969) / 4
+ + ((st.wYear % 4)
+ ? days_in_preceding_months[st.wMonth - 1]
+ : days_in_preceding_months_leap[st.wMonth - 1])
+ + st.wDay - 1);
+
+ *abs_sec = st.wSecond + 60 * (st.wMinute + 60 * (st.wHour + 24 * days));
+}
+
+void
+omni_thread::stacksize(unsigned long sz)
+{
+ stack_size = sz;
+}
+
+unsigned long
+omni_thread::stacksize()
+{
+ return stack_size;
+}
+
+//
+// Dummy thread
+//
+
+class omni_thread_dummy : public omni_thread {
+public:
+ inline omni_thread_dummy() : omni_thread()
+ {
+ _dummy = 1;
+ _state = STATE_RUNNING;
+
+ if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
+ GetCurrentProcess(), &handle,
+ 0, FALSE, DUPLICATE_SAME_ACCESS))
+ throw omni_thread_fatal(GetLastError());
+
+ nt_id = GetCurrentThreadId();
+
+ if (!TlsSetValue(self_tls_index, (LPVOID)this))
+ throw omni_thread_fatal(GetLastError());
+ }
+ inline ~omni_thread_dummy()
+ {
+ if (!TlsSetValue(self_tls_index, (LPVOID)0))
+ throw omni_thread_fatal(GetLastError());
+ }
+};
+
+omni_thread*
+omni_thread::create_dummy()
+{
+ if (omni_thread::self())
+ throw omni_thread_invalid();
+
+ return new omni_thread_dummy;
+}
+
+void
+omni_thread::release_dummy()
+{
+ omni_thread* self = omni_thread::self();
+ if (!self || !self->_dummy)
+ throw omni_thread_invalid();
+
+ omni_thread_dummy* dummy = (omni_thread_dummy*)self;
+ delete dummy;
+}
+
+
+#if defined(__DMC__) && defined(_WINDLL)
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ return TRUE;
+}
+#endif
+
+
+#define INSIDE_THREAD_IMPL_CC
+#include "threaddata.cc"
+#undef INSIDE_THREAD_IMPL_CC
diff --git a/omnithread/omnithread.h b/omnithread/omnithread.h
new file mode 100644
index 000000000..b6df34d72
--- /dev/null
+++ b/omnithread/omnithread.h
@@ -0,0 +1,622 @@
+// -*- Mode: C++; -*-
+// Package : omnithread
+// omnithread.h Created : 7/94 tjr
+//
+// Copyright (C) 2006 Free Software Foundation, Inc.
+// Copyright (C) 1994,1995,1996, 1997 Olivetti & Oracle Research Laboratory
+//
+// This file is part of the omnithread library
+//
+// The omnithread library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free
+// Software Foundation, Inc., 51 Franklin Street, Boston, MA
+// 02110-1301, USA
+//
+
+//
+// Interface to OMNI thread abstraction.
+//
+// This file declares classes for threads and synchronisation objects
+// (mutexes, condition variables and counting semaphores).
+//
+// Wherever a seemingly arbitrary choice has had to be made as to the interface
+// provided, the intention here has been to be as POSIX-like as possible. This
+// is why there is no semaphore timed wait, for example.
+//
+
+#ifndef __omnithread_h_
+#define __omnithread_h_
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+class omni_mutex;
+class omni_condition;
+class omni_semaphore;
+class omni_thread;
+
+//
+// OMNI_THREAD_EXPOSE can be defined as public or protected to expose the
+// implementation class - this may be useful for debugging. Hopefully this
+// won't change the underlying structure which the compiler generates so that
+// this can work without recompiling the library.
+//
+
+#ifndef OMNI_THREAD_EXPOSE
+#define OMNI_THREAD_EXPOSE private
+#endif
+
+//
+// Include implementation-specific header file.
+//
+// This must define 4 CPP macros of the form OMNI_x_IMPLEMENTATION for mutex,
+// condition variable, semaphore and thread. Each should define any
+// implementation-specific members of the corresponding classes.
+//
+
+
+//
+// For now, we assume they've always got a Posix Threads implementation.
+// If not, it'll take some configure hacking to sort it out, along with
+// the relevant libraries to link with, etc.
+//
+
+#if !defined(OMNITHREAD_POSIX) && !defined(OMNITHREAD_NT) && defined HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if defined(OMNITHREAD_POSIX)
+#include <ot_posix.h>
+
+#elif defined(OMNITHREAD_NT)
+#include <ot_nt.h>
+
+#ifdef _MSC_VER
+
+// Using MSVC++ to compile. If compiling library as a DLL,
+// define _OMNITHREAD_DLL. If compiling as a statuc library, define
+// _WINSTATIC
+// If compiling an application that is to be statically linked to omnithread,
+// define _WINSTATIC (if the application is to be dynamically linked,
+// there is no need to define any of these macros).
+
+#if defined (_OMNITHREAD_DLL) && defined(_WINSTATIC)
+#error "Both _OMNITHREAD_DLL and _WINSTATIC are defined."
+#elif defined(_OMNITHREAD_DLL)
+#define _OMNITHREAD_NTDLL_ __declspec(dllexport)
+#elif !defined(_WINSTATIC)
+#define _OMNITHREAD_NTDLL_ __declspec(dllimport)
+#elif defined(_WINSTATIC)
+#define _OMNITHREAD_NTDLL_
+#endif
+ // _OMNITHREAD_DLL && _WINSTATIC
+
+#else
+
+// Not using MSVC++ to compile
+#define _OMNITHREAD_NTDLL_
+
+#endif
+ // _MSC_VER
+
+#elif defined(__vxWorks__)
+#include <ot_VxThread.h>
+
+#elif defined(__sunos__)
+#if __OSVERSION__ != 5
+// XXX Workaround for SUN C++ compiler (seen on 4.2) Template.DB code
+// regeneration bug. See omniORB2/CORBA_sysdep.h for details.
+#if !defined(__SUNPRO_CC) || __OSVERSION__ != '5'
+#error "Only SunOS 5.x or later is supported."
+#endif
+#endif
+#ifdef UseSolarisThreads
+#include <ot_solaris.h>
+#else
+#include <ot_posix.h>
+#endif
+
+#elif defined(__rtems__)
+#include <ot_posix.h>
+#include <sched.h>
+
+#elif defined(__macos__)
+#include <ot_posix.h>
+#include <sched.h>
+
+#else
+#error "No implementation header file"
+#endif
+
+
+#if !defined(__WIN32__)
+#define _OMNITHREAD_NTDLL_
+#endif
+
+#if (!defined(OMNI_MUTEX_IMPLEMENTATION) || \
+ !defined(OMNI_MUTEX_LOCK_IMPLEMENTATION) || \
+ !defined(OMNI_MUTEX_TRYLOCK_IMPLEMENTATION)|| \
+ !defined(OMNI_MUTEX_UNLOCK_IMPLEMENTATION) || \
+ !defined(OMNI_CONDITION_IMPLEMENTATION) || \
+ !defined(OMNI_SEMAPHORE_IMPLEMENTATION) || \
+ !defined(OMNI_THREAD_IMPLEMENTATION))
+#error "Implementation header file incomplete"
+#endif
+
+
+//
+// This exception is thrown in the event of a fatal error.
+//
+
+class _OMNITHREAD_NTDLL_ omni_thread_fatal {
+public:
+ int error;
+ omni_thread_fatal(int e = 0) : error(e) {}
+};
+
+
+//
+// This exception is thrown when an operation is invoked with invalid
+// arguments.
+//
+
+class _OMNITHREAD_NTDLL_ omni_thread_invalid {};
+
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Mutex
+//
+///////////////////////////////////////////////////////////////////////////
+
+class _OMNITHREAD_NTDLL_ omni_mutex {
+
+public:
+ omni_mutex(void);
+ ~omni_mutex(void);
+
+ inline void lock(void) { OMNI_MUTEX_LOCK_IMPLEMENTATION }
+ inline void unlock(void) { OMNI_MUTEX_UNLOCK_IMPLEMENTATION }
+ inline int trylock(void) { return OMNI_MUTEX_TRYLOCK_IMPLEMENTATION }
+ // if mutex is unlocked, lock it and return 1 (true).
+ // If it's already locked then return 0 (false).
+
+ inline void acquire(void) { lock(); }
+ inline void release(void) { unlock(); }
+ // the names lock and unlock are preferred over acquire and release
+ // since we are attempting to be as POSIX-like as possible.
+
+ friend class omni_condition;
+
+private:
+ // dummy copy constructor and operator= to prevent copying
+ omni_mutex(const omni_mutex&);
+ omni_mutex& operator=(const omni_mutex&);
+
+OMNI_THREAD_EXPOSE:
+ OMNI_MUTEX_IMPLEMENTATION
+};
+
+//
+// As an alternative to:
+// {
+// mutex.lock();
+// .....
+// mutex.unlock();
+// }
+//
+// you can use a single instance of the omni_mutex_lock class:
+//
+// {
+// omni_mutex_lock l(mutex);
+// ....
+// }
+//
+// This has the advantage that mutex.unlock() will be called automatically
+// when an exception is thrown.
+//
+
+class _OMNITHREAD_NTDLL_ omni_mutex_lock {
+ omni_mutex& mutex;
+public:
+ omni_mutex_lock(omni_mutex& m) : mutex(m) { mutex.lock(); }
+ ~omni_mutex_lock(void) { mutex.unlock(); }
+private:
+ // dummy copy constructor and operator= to prevent copying
+ omni_mutex_lock(const omni_mutex_lock&);
+ omni_mutex_lock& operator=(const omni_mutex_lock&);
+};
+
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Condition variable
+//
+///////////////////////////////////////////////////////////////////////////
+
+class _OMNITHREAD_NTDLL_ omni_condition {
+
+ omni_mutex* mutex;
+
+public:
+ omni_condition(omni_mutex* m);
+ // constructor must be given a pointer to an existing mutex. The
+ // condition variable is then linked to the mutex, so that there is an
+ // implicit unlock and lock around wait() and timed_wait().
+
+ ~omni_condition(void);
+
+ void wait(void);
+ // wait for the condition variable to be signalled. The mutex is
+ // implicitly released before waiting and locked again after waking up.
+ // If wait() is called by multiple threads, a signal may wake up more
+ // than one thread. See POSIX threads documentation for details.
+
+ int timedwait(unsigned long secs, unsigned long nanosecs = 0);
+ // timedwait() is given an absolute time to wait until. To wait for a
+ // relative time from now, use omni_thread::get_time. See POSIX threads
+ // documentation for why absolute times are better than relative.
+ // Returns 1 (true) if successfully signalled, 0 (false) if time
+ // expired.
+
+ void signal(void);
+ // if one or more threads have called wait(), signal wakes up at least
+ // one of them, possibly more. See POSIX threads documentation for
+ // details.
+
+ void broadcast(void);
+ // broadcast is like signal but wakes all threads which have called
+ // wait().
+
+private:
+ // dummy copy constructor and operator= to prevent copying
+ omni_condition(const omni_condition&);
+ omni_condition& operator=(const omni_condition&);
+
+OMNI_THREAD_EXPOSE:
+ OMNI_CONDITION_IMPLEMENTATION
+};
+
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Counting (or binary) semaphore
+//
+///////////////////////////////////////////////////////////////////////////
+
+class _OMNITHREAD_NTDLL_ omni_semaphore {
+
+public:
+ // if max_count == 1, you've got a binary semaphore.
+ omni_semaphore(unsigned int initial = 1, unsigned int max_count = 0x7fffffff);
+ ~omni_semaphore(void);
+
+ void wait(void);
+ // if semaphore value is > 0 then decrement it and carry on. If it's
+ // already 0 then block.
+
+ int trywait(void);
+ // if semaphore value is > 0 then decrement it and return 1 (true).
+ // If it's already 0 then return 0 (false).
+
+ void post(void);
+ // if any threads are blocked in wait(), wake one of them up. Otherwise
+ // increment the value of the semaphore.
+
+private:
+ // dummy copy constructor and operator= to prevent copying
+ omni_semaphore(const omni_semaphore&);
+ omni_semaphore& operator=(const omni_semaphore&);
+
+OMNI_THREAD_EXPOSE:
+ OMNI_SEMAPHORE_IMPLEMENTATION
+};
+
+//
+// A helper class for semaphores, similar to omni_mutex_lock above.
+//
+
+class _OMNITHREAD_NTDLL_ omni_semaphore_lock {
+ omni_semaphore& sem;
+public:
+ omni_semaphore_lock(omni_semaphore& s) : sem(s) { sem.wait(); }
+ ~omni_semaphore_lock(void) { sem.post(); }
+private:
+ // dummy copy constructor and operator= to prevent copying
+ omni_semaphore_lock(const omni_semaphore_lock&);
+ omni_semaphore_lock& operator=(const omni_semaphore_lock&);
+};
+
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Thread
+//
+///////////////////////////////////////////////////////////////////////////
+
+class _OMNITHREAD_NTDLL_ omni_thread {
+
+public:
+
+ enum priority_t {
+ PRIORITY_LOW,
+ PRIORITY_NORMAL,
+ PRIORITY_HIGH
+ };
+
+ enum state_t {
+ STATE_NEW, // thread object exists but thread hasn't
+ // started yet.
+ STATE_RUNNING, // thread is running.
+ STATE_TERMINATED // thread has terminated but storage has not
+ // been reclaimed (i.e. waiting to be joined).
+ };
+
+ //
+ // Constructors set up the thread object but the thread won't start until
+ // start() is called. The create method can be used to construct and start
+ // a thread in a single call.
+ //
+
+ omni_thread(void (*fn)(void*), void* arg = NULL,
+ priority_t pri = PRIORITY_NORMAL);
+ omni_thread(void* (*fn)(void*), void* arg = NULL,
+ priority_t pri = PRIORITY_NORMAL);
+ // these constructors create a thread which will run the given function
+ // when start() is called. The thread will be detached if given a
+ // function with void return type, undetached if given a function
+ // returning void*. If a thread is detached, storage for the thread is
+ // reclaimed automatically on termination. Only an undetached thread
+ // can be joined.
+
+ void start(void);
+ // start() causes a thread created with one of the constructors to
+ // start executing the appropriate function.
+
+protected:
+
+ omni_thread(void* arg = NULL, priority_t pri = PRIORITY_NORMAL);
+ // this constructor is used in a derived class. The thread will
+ // execute the run() or run_undetached() member functions depending on
+ // whether start() or start_undetached() is called respectively.
+
+ void start_undetached(void);
+ // can be used with the above constructor in a derived class to cause
+ // the thread to be undetached. In this case the thread executes the
+ // run_undetached member function.
+
+ virtual ~omni_thread(void);
+ // destructor cannot be called by user (except via a derived class).
+ // Use exit() or cancel() instead. This also means a thread object must
+ // be allocated with new - it cannot be statically or automatically
+ // allocated. The destructor of a class that inherits from omni_thread
+ // shouldn't be public either (otherwise the thread object can be
+ // destroyed while the underlying thread is still running).
+
+public:
+
+ void join(void**);
+ // join causes the calling thread to wait for another's completion,
+ // putting the return value in the variable of type void* whose address
+ // is given (unless passed a null pointer). Only undetached threads
+ // may be joined. Storage for the thread will be reclaimed.
+
+ void set_priority(priority_t);
+ // set the priority of the thread.
+
+ static omni_thread* create(void (*fn)(void*), void* arg = NULL,
+ priority_t pri = PRIORITY_NORMAL);
+ static omni_thread* create(void* (*fn)(void*), void* arg = NULL,
+ priority_t pri = PRIORITY_NORMAL);
+ // create spawns a new thread executing the given function with the
+ // given argument at the given priority. Returns a pointer to the
+ // thread object. It simply constructs a new thread object then calls
+ // start.
+
+ static void exit(void* return_value = NULL);
+ // causes the calling thread to terminate.
+
+ static omni_thread* self(void);
+ // returns the calling thread's omni_thread object. If the
+ // calling thread is not the main thread and is not created
+ // using this library, returns 0. (But see create_dummy()
+ // below.)
+
+ static void yield(void);
+ // allows another thread to run.
+
+ static void sleep(unsigned long secs, unsigned long nanosecs = 0);
+ // sleeps for the given time.
+
+ static void get_time(unsigned long* abs_sec, unsigned long* abs_nsec,
+ unsigned long rel_sec = 0, unsigned long rel_nsec=0);
+ // calculates an absolute time in seconds and nanoseconds, suitable for
+ // use in timed_waits on condition variables, which is the current time
+ // plus the given relative offset.
+
+
+ static void stacksize(unsigned long sz);
+ static unsigned long stacksize();
+ // Use this value as the stack size when spawning a new thread.
+ // The default value (0) means that the thread library default is
+ // to be used.
+
+
+ // Per-thread data
+ //
+ // These functions allow you to attach additional data to an
+ // omni_thread. First allocate a key for yourself with
+ // allocate_key(). Then you can store any object whose class is
+ // derived from value_t. Any values still stored in the
+ // omni_thread when the thread exits are deleted.
+ //
+ // These functions are NOT thread safe, so you should be very
+ // careful about setting/getting data in a different thread to the
+ // current thread.
+
+ typedef unsigned int key_t;
+ static key_t allocate_key();
+
+ class value_t {
+ public:
+ virtual ~value_t() {}
+ };
+
+ value_t* set_value(key_t k, value_t* v);
+ // Sets a value associated with the given key. The key must
+ // have been allocated with allocate_key(). If a value has
+ // already been set with the specified key, the old value_t
+ // object is deleted and replaced. Returns the value which was
+ // set, or zero if the key is invalid.
+
+ value_t* get_value(key_t k);
+ // Returns the value associated with the key. If the key is
+ // invalid, or there is no value for the key, returns zero.
+
+ value_t* remove_value(key_t k);
+ // Removes the value associated with the key and returns it.
+ // If the key is invalid, or there is no value for the key,
+ // returns zero.
+
+
+ // Dummy omni_thread
+ //
+ // Sometimes, an application finds itself with threads created
+ // outside of omnithread which must interact with omnithread
+ // features such as the per-thread data. In this situation,
+ // omni_thread::self() would normally return 0. These functions
+ // allow the application to create a suitable dummy omni_thread
+ // object.
+
+ static omni_thread* create_dummy(void);
+ // creates a dummy omni_thread for the calling thread. Future
+ // calls to self() will return the dummy omni_thread. Throws
+ // omni_thread_invalid if this thread already has an
+ // associated omni_thread (real or dummy).
+
+ static void release_dummy();
+ // release the dummy omni_thread for this thread. This
+ // function MUST be called before the thread exits. Throws
+ // omni_thread_invalid if the calling thread does not have a
+ // dummy omni_thread.
+
+ // class ensure_self should be created on the stack. If created in
+ // a thread without an associated omni_thread, it creates a dummy
+ // thread which is released when the ensure_self object is deleted.
+
+ class ensure_self {
+ public:
+ inline ensure_self() : _dummy(0)
+ {
+ _self = omni_thread::self();
+ if (!_self) {
+ _dummy = 1;
+ _self = omni_thread::create_dummy();
+ }
+ }
+ inline ~ensure_self()
+ {
+ if (_dummy)
+ omni_thread::release_dummy();
+ }
+ inline omni_thread* self() { return _self; }
+ private:
+ omni_thread* _self;
+ int _dummy;
+ };
+
+
+private:
+
+ virtual void run(void* /*arg*/) {}
+ virtual void* run_undetached(void* /*arg*/) { return NULL; }
+ // can be overridden in a derived class. When constructed using the
+ // the constructor omni_thread(void*, priority_t), these functions are
+ // called by start() and start_undetached() respectively.
+
+ void common_constructor(void* arg, priority_t pri, int det);
+ // implements the common parts of the constructors.
+
+ omni_mutex mutex;
+ // used to protect any members which can change after construction,
+ // i.e. the following 2 members.
+
+ state_t _state;
+ priority_t _priority;
+
+ static omni_mutex* next_id_mutex;
+ static int next_id;
+ int _id;
+
+ void (*fn_void)(void*);
+ void* (*fn_ret)(void*);
+ void* thread_arg;
+ int detached;
+ int _dummy;
+ value_t** _values;
+ unsigned long _value_alloc;
+
+ omni_thread(const omni_thread&);
+ omni_thread& operator=(const omni_thread&);
+ // Not implemented
+
+public:
+
+ priority_t priority(void) {
+
+ // return this thread's priority.
+
+ omni_mutex_lock l(mutex);
+ return _priority;
+ }
+
+ state_t state(void) {
+
+ // return thread state (invalid, new, running or terminated).
+
+ omni_mutex_lock l(mutex);
+ return _state;
+ }
+
+ int id(void) { return _id; }
+ // return unique thread id within the current process.
+
+
+ // This class plus the instance of it declared below allows us to execute
+ // some initialisation code before main() is called.
+
+ class _OMNITHREAD_NTDLL_ init_t {
+ public:
+ init_t(void);
+ ~init_t(void);
+ };
+
+ friend class init_t;
+ friend class omni_thread_dummy;
+
+OMNI_THREAD_EXPOSE:
+ OMNI_THREAD_IMPLEMENTATION
+};
+
+#ifndef __rtems__
+static omni_thread::init_t omni_thread_init;
+#else
+// RTEMS calls global Ctor/Dtor in a context that is not
+// a posix thread. Calls to functions to pthread_self() in
+// that context returns NULL.
+// So, for RTEMS we will make the thread initialization at the
+// beginning of the Init task that has a posix context.
+#endif
+
+#endif
diff --git a/omnithread/ot_VxThread.h b/omnithread/ot_VxThread.h
new file mode 100644
index 000000000..e96c036cc
--- /dev/null
+++ b/omnithread/ot_VxThread.h
@@ -0,0 +1,118 @@
+#ifndef __VXTHREAD_H__
+#define __VXTHREAD_H__
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Project: omniORB
+%% Filename: $Filename$
+%% Author: Guillaume/Bill ARRECKX
+%% Copyright Wavetek Wandel & Goltermann, Plymouth.
+%% Description: OMNI thread implementation classes for VxWorks threads
+%% Notes:
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% $Log$
+%% Revision 1.1 2004/04/10 18:00:52 eb
+%% Initial revision
+%%
+%% Revision 1.1.1.1 2004/03/01 00:20:27 eb
+%% initial checkin
+%%
+%% Revision 1.1 2003/05/25 05:29:04 eb
+%% see ChangeLog
+%%
+%% Revision 1.1.2.1 2003/02/17 02:03:07 dgrisby
+%% vxWorks port. (Thanks Michael Sturm / Acterna Eningen GmbH).
+%%
+%% Revision 1.1.1.1 2002/11/19 14:55:21 sokcevti
+%% OmniOrb4.0.0 VxWorks port
+%%
+%% Revision 1.2 2002/06/14 12:45:50 engeln
+%% unnecessary members in condition removed.
+%% ---
+%%
+%% Revision 1.1.1.1 2002/04/02 10:08:49 sokcevti
+%% omniORB4 initial realease
+%%
+%% Revision 1.1 2001/03/23 16:50:23 hartmut
+%% Initial Version 2.8
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+*/
+
+
+///////////////////////////////////////////////////////////////////////////
+// Includes
+///////////////////////////////////////////////////////////////////////////
+#include <vxWorks.h>
+#include <semLib.h>
+#include <taskLib.h>
+
+
+///////////////////////////////////////////////////////////////////////////
+// Externs prototypes
+///////////////////////////////////////////////////////////////////////////
+extern "C" void omni_thread_wrapper(void* ptr);
+
+
+///////////////////////////////////////////////////////////////////////////
+// Exported macros
+// Note: These are added as private members in each class implementation.
+///////////////////////////////////////////////////////////////////////////
+#define OMNI_MUTEX_IMPLEMENTATION \
+ SEM_ID mutexID; \
+ bool m_bConstructed;
+
+#define OMNI_CONDITION_IMPLEMENTATION \
+ long waiters_; \
+ SEM_ID waiters_lock_; \
+ SEM_ID sema_;
+
+#define OMNI_SEMAPHORE_IMPLEMENTATION \
+ SEM_ID semID;
+
+#define OMNI_MUTEX_LOCK_IMPLEMENTATION \
+ if(semTake(mutexID, WAIT_FOREVER) != OK) \
+ { \
+ throw omni_thread_fatal(errno); \
+ }
+
+#define OMNI_MUTEX_UNLOCK_IMPLEMENTATION \
+ if(semGive(mutexID) != OK) \
+ { \
+ throw omni_thread_fatal(errno); \
+ }
+
+#define OMNI_THREAD_IMPLEMENTATION \
+ friend void omni_thread_wrapper(void* ptr); \
+ static int vxworks_priority(priority_t); \
+ omni_condition *running_cond; \
+ void* return_val; \
+ int tid; \
+ public: \
+ static void attach(void); \
+ static void detach(void); \
+ static void show(void);
+
+
+///////////////////////////////////////////////////////////////////////////
+// Porting macros
+///////////////////////////////////////////////////////////////////////////
+// This is a wrapper function for the 'main' function which does not exists
+// as such in VxWorks. The wrapper creates a launch function instead,
+// which spawns the application wrapped in a omni_thread.
+// Argc will always be null.
+///////////////////////////////////////////////////////////////////////////
+#define main( discarded_argc, discarded_argv ) \
+ omni_discard_retval() \
+ { \
+ throw; \
+ } \
+ int omni_main( int argc, char **argv ); \
+ void launch( ) \
+ { \
+ omni_thread* th = new omni_thread( (void(*)(void*))omni_main );\
+ th->start();\
+ }\
+ int omni_main( int argc, char **argv )
+
+
+#endif // ndef __VXTHREAD_H__
diff --git a/omnithread/ot_mach.h b/omnithread/ot_mach.h
new file mode 100644
index 000000000..76361926c
--- /dev/null
+++ b/omnithread/ot_mach.h
@@ -0,0 +1,51 @@
+// Package : omnithread
+// omnithread/posix.h Created : 7/97 lars immisch lars@ibp.de
+//
+// Copyright (C) 1994,1995,1996, 1997 Immisch, becker & Partner
+//
+// This file is part of the omnithread library
+//
+// The omnithread library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free
+// Software Foundation, Inc., 51 Franklin Street, Boston, MA
+// 02110-1301, USA
+//
+//
+// OMNI thread implementation classes for posix threads
+//
+
+#ifndef __omnithread_mach_h_
+#define __omnithread_mach_h_
+
+#include <mach/cthreads.h>
+
+extern "C" void* omni_thread_wrapper(void* ptr);
+
+#define OMNI_MUTEX_IMPLEMENTATION \
+ struct mutex mach_mutex;
+
+#define OMNI_CONDITION_IMPLEMENTATION \
+ struct condition mach_cond;
+
+#define OMNI_SEMAPHORE_IMPLEMENTATION \
+ omni_mutex m; \
+ omni_condition c; \
+ int value;
+
+
+#define OMNI_THREAD_IMPLEMENTATION \
+ cthread_t mach_thread; \
+ static int mach_priority(priority_t); \
+ friend void* omni_thread_wrapper(void* ptr);
+
+#endif
diff --git a/omnithread/ot_nt.h b/omnithread/ot_nt.h
new file mode 100644
index 000000000..551ccf2f1
--- /dev/null
+++ b/omnithread/ot_nt.h
@@ -0,0 +1,85 @@
+// Package : omnithread
+// omnithread/nt.h Created : 6/95 tjr
+//
+// Copyright (C) 1995, 1996, 1997 Olivetti & Oracle Research Laboratory
+//
+// This file is part of the omnithread library
+//
+// The omnithread library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free
+// Software Foundation, Inc., 51 Franklin Street, Boston, MA
+// 02110-1301, USA
+//
+//
+// OMNI thread implementation classes for NT threads.
+//
+
+#ifndef __omnithread_nt_h_
+#define __omnithread_nt_h_
+
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# define OMNI_DEFINED_WIN32_LEAN_AND_MEAN
+#endif
+
+#include <windows.h>
+
+#ifdef OMNI_DEFINED_WIN32_LEAN_AND_MEAN
+# undef WIN32_LEAN_AND_MEAN
+# undef OMNI_DEFINED_WIN32_LEAN_AND_MEAN
+#endif
+
+
+#ifndef __BCPLUSPLUS__
+#define OMNI_THREAD_WRAPPER \
+ unsigned __stdcall omni_thread_wrapper(LPVOID ptr);
+#else
+#define OMNI_THREAD_WRAPPER \
+ void _USERENTRY omni_thread_wrapper(void *ptr);
+#endif
+
+extern "C" OMNI_THREAD_WRAPPER;
+
+#define OMNI_MUTEX_IMPLEMENTATION \
+ CRITICAL_SECTION crit;
+
+#define OMNI_MUTEX_LOCK_IMPLEMENTATION \
+ EnterCriticalSection(&crit);
+
+#define OMNI_MUTEX_TRYLOCK_IMPLEMENTATION \
+ TryEnterCriticalSection(&crit);
+
+#define OMNI_MUTEX_UNLOCK_IMPLEMENTATION \
+ LeaveCriticalSection(&crit);
+
+#define OMNI_CONDITION_IMPLEMENTATION \
+ CRITICAL_SECTION crit; \
+ omni_thread* waiting_head; \
+ omni_thread* waiting_tail;
+
+#define OMNI_SEMAPHORE_IMPLEMENTATION \
+ HANDLE nt_sem;
+
+#define OMNI_THREAD_IMPLEMENTATION \
+ HANDLE handle; \
+ DWORD nt_id; \
+ void* return_val; \
+ HANDLE cond_semaphore; \
+ omni_thread* cond_next; \
+ omni_thread* cond_prev; \
+ BOOL cond_waiting; \
+ static int nt_priority(priority_t); \
+ friend class omni_condition; \
+ friend OMNI_THREAD_WRAPPER;
+
+#endif
diff --git a/omnithread/ot_posix.h b/omnithread/ot_posix.h
new file mode 100644
index 000000000..666ccc089
--- /dev/null
+++ b/omnithread/ot_posix.h
@@ -0,0 +1,81 @@
+// Package : omnithread
+// omnithread/posix.h Created : 7/94 tjr
+//
+// Copyright (C) 2006 Free Software Foundation, Inc.
+// Copyright (C) 1994,1995,1996, 1997 Olivetti & Oracle Research Laboratory
+//
+// This file is part of the omnithread library
+//
+// The omnithread library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free
+// Software Foundation, Inc., 51 Franklin Street, Boston, MA
+// 02110-1301, USA
+//
+//
+// OMNI thread implementation classes for posix threads
+//
+
+#ifndef __omnithread_posix_h_
+#define __omnithread_posix_h_
+
+#if defined(__alpha__) && defined(__osf1__) || defined(__hpux__)
+// stop unnecessary definitions of TRY, etc on OSF
+#ifndef EXC_HANDLING
+#define EXC_HANDLING
+#endif
+#endif
+
+#ifndef __POSIX_NT__
+# include <pthread.h>
+#else
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# define OMNI_DEFINED_WIN32_LEAN_AND_MEAN
+# endif
+# include <windows.h>
+# include "pthread_nt.h"
+# ifdef OMNI_DEFINED_WIN32_LEAN_AND_MEAN
+# undef WIN32_LEAN_AND_MEAN
+# undef OMNI_DEFINED_WIN32_LEAN_AND_MEAN
+# endif
+#endif
+
+extern "C" void* omni_thread_wrapper(void* ptr);
+
+#define OMNI_MUTEX_IMPLEMENTATION \
+ pthread_mutex_t posix_mutex;
+
+#define OMNI_MUTEX_LOCK_IMPLEMENTATION \
+ pthread_mutex_lock(&posix_mutex);
+
+#define OMNI_MUTEX_TRYLOCK_IMPLEMENTATION \
+ (pthread_mutex_trylock(&posix_mutex)==0);
+
+#define OMNI_MUTEX_UNLOCK_IMPLEMENTATION \
+ pthread_mutex_unlock(&posix_mutex);
+
+#define OMNI_CONDITION_IMPLEMENTATION \
+ pthread_cond_t posix_cond;
+
+#define OMNI_SEMAPHORE_IMPLEMENTATION \
+ omni_mutex m; \
+ omni_condition c; \
+ int value; \
+ int max_count;
+
+#define OMNI_THREAD_IMPLEMENTATION \
+ pthread_t posix_thread; \
+ static int posix_priority(priority_t); \
+ friend void* omni_thread_wrapper(void* ptr);
+
+#endif
diff --git a/omnithread/ot_pthread_nt.h b/omnithread/ot_pthread_nt.h
new file mode 100644
index 000000000..dbf4356cf
--- /dev/null
+++ b/omnithread/ot_pthread_nt.h
@@ -0,0 +1,186 @@
+/* Package : omnithread
+ omnithread/pthread_nt.h Created : Steven Brenneis <brennes1@rjrt.com>
+
+ Copyright (C) 1998 Steven Brennes
+
+ This file is part of the omnithread library
+
+ The omnithread library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin Street, Boston, MA
+ 02110-1301, USA
+
+ Posix Threads implementation for Windows NT, version 4.0
+*/
+
+#ifndef PTHREAD_NT_H_INCLUDED
+#define PTHREAD_NT_H_INCLUDED
+
+#include <errno.h>
+
+#ifndef ETIMEDOUT
+// May have to be changed if NT starts supporting more errno values
+#define ETIMEDOUT 60
+#endif
+
+#undef PthreadDraftVersion
+#define PthreadDraftVersion 10
+
+#define NoNanoSleep
+
+#define PthreadSupportThreadPriority
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _TIMERS_T_
+#define _TIMERS_T_
+ typedef struct timespec {
+ unsigned long tv_sec;
+ long tv_nsec;
+ } timespec_t;
+#endif
+
+typedef char* __pthreadLongString_t;
+typedef void* __pthreadLongAddr_t;
+typedef __pthreadLongAddr_t* __pthreadLongAddr_p;
+typedef long __pthreadLongInt_t;
+typedef unsigned long __pthreadLongUint_t;
+typedef __pthreadLongAddr_p __pthreadTsd_t;
+
+typedef struct __pthread_mutex_t {
+ unsigned int lock; /* LOCK, SLOW, TYPE, RECURSIVE */
+ unsigned int valid; /* Validation info */
+ __pthreadLongString_t name; /* Name of mutex */
+ unsigned int arg; /* printf argument for name */
+ unsigned int depth; /* Recursive lock depth */
+ unsigned long sequence; /* Mutex sequence number */
+ unsigned long owner; /* Current owner (if known */
+ __pthreadLongAddr_t block; /* Pointer to blocking struct */
+} pthread_mutex_t;
+
+typedef struct __pthread_mutexattr_t {
+ long valid;
+ __pthreadLongUint_t reserved[15];
+} pthread_mutexattr_t;
+
+typedef struct __pthread_cond_t {
+ unsigned int state; /* EVENT, SLOW, REFCNT */
+ unsigned int valid; /* Validation info */
+ __pthreadLongString_t name; /* Name of condition variable */
+ unsigned int arg; /* printf argument for name */
+ unsigned long sequence; /* Condition variable seq # */
+ __pthreadLongAddr_t block; /* Pointer to blocking struct */
+} pthread_cond_t ;
+
+typedef struct __pthread_condattr_t {
+ long valid;
+ __pthreadLongUint_t reserved[13];
+} pthread_condattr_t ;
+
+typedef struct __pthread_transp_t {
+ __pthreadLongAddr_t reserved1; /* Reserved to posix_nt */
+ __pthreadLongAddr_t reserved2; /* Reserved to posix_nt */
+ unsigned short size; /* Size of data structure */
+ unsigned char reserved3[2]; /* Reserved to posix_nt */
+ __pthreadLongAddr_t reserved4; /* Reserved to posix_nt */
+ __pthreadLongUint_t sequence; /* Thread sequence number */
+ __pthreadLongUint_t reserved5[2]; /* Reserved to posix_nt */
+ __pthreadLongAddr_t per_kt_area; /* Pointer to kernel context */
+ __pthreadLongAddr_t stack_base; /* Current stack base */
+ __pthreadLongAddr_t stack_reserve; /* Current stack reserve zone */
+ __pthreadLongAddr_t stack_yellow; /* Current stack yellow zone */
+ __pthreadLongAddr_t stack_guard; /* Current stack guard zone */
+ __pthreadLongUint_t stack_size; /* Size of stack */
+ __pthreadTsd_t tsd_values; /* TSD array (indexed by key) */
+ unsigned long tsd_count; /* Number of TSD cells */
+ __pthreadLongAddr_t reserved6; /* Reserved to posix_nt */
+ __pthreadLongAddr_t reserved7; /* Reserved to posix_nt */
+ unsigned int thread_flags; /* Dynamic external state */
+} pthread_transp_t, *pthread_transp_p;
+
+typedef pthread_transp_p pthread_t;
+
+typedef struct __pthread_attr_t {
+ long valid;
+ __pthreadLongString_t name;
+ __pthreadLongUint_t arg;
+ __pthreadLongUint_t reserved[19];
+} pthread_attr_t ;
+
+typedef unsigned int pthread_key_t;
+
+typedef struct sched_param {
+ int sched_priority;
+} sched_param_t;
+
+/* Function Prototypes */
+
+int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
+ void *(*start_routine)(void*), void *arg);
+int pthread_detach(pthread_t thread);
+int pthread_join(pthread_t thread, void **value_ptr);
+void pthread_exit(void *value_ptr);
+int pthread_attr_init(pthread_attr_t *attr);
+int pthread_attr_destroy(pthread_attr_t *attr);
+int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
+int pthread_attr_getstacksize(const pthread_attr_t *attr,
+ size_t *stacksize);
+int pthread_cond_init(pthread_cond_t *cond,
+ const pthread_condattr_t *attr);
+int pthread_cond_destroy(pthread_cond_t *cond);
+int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
+int pthread_cond_timedwait(pthread_cond_t *cond,
+ pthread_mutex_t *mutex,
+ const struct timespec *abstime);
+int pthread_cond_signal(pthread_cond_t *cond);
+int pthread_cond_broadcast(pthread_cond_t *cond);
+int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
+int pthread_key_delete(pthread_key_t key);
+int pthread_mutex_destroy(pthread_mutex_t *mutex);
+int pthread_mutex_init(pthread_mutex_t *mutex,
+ const pthread_mutexattr_t *attr);
+int pthread_mutex_lock(pthread_mutex_t *mutex);
+int pthread_mutex_trylock(pthread_mutex_t *mutex);
+int pthread_mutex_unlock(pthread_mutex_t *mutex);
+pthread_t pthread_self();
+int pthread_setspecific(pthread_key_t key, const void *value);
+void *pthread_getspecific(pthread_key_t key);
+int pthread_getschedparam(pthread_t thread, int *policy,
+ struct sched_param *param);
+int pthread_setschedparam(pthread_t thread, int policy,
+ const struct sched_param *param);
+int pthread_attr_setschedparam(pthread_attr_t *attr,
+ const struct sched_param *param);
+int pthread_attr_getschedparam(const pthread_attr_t *attr,
+ struct sched_param *param);
+
+int pthread_delay_np(const struct timespec *interval);
+int pthread_get_expiration_np(const struct timespec *delta,
+ struct timespec *abstime);
+
+# define SCHED_FIFO 1
+# define SCHED_RR 2
+# define SCHED_OTHER 3
+
+int sched_yield();
+int sched_get_priority_max(int policy);
+int sched_get_priority_min(int policy);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // PTHREAD_NT_H_INCLUDED
diff --git a/omnithread/ot_solaris.h b/omnithread/ot_solaris.h
new file mode 100644
index 000000000..f4fea0b11
--- /dev/null
+++ b/omnithread/ot_solaris.h
@@ -0,0 +1,47 @@
+// Package : omnithread
+// omnithread/solaris.h Created : 7/94 tjr
+//
+// Copyright (C) 1994,1995,1996, 1997 Olivetti & Oracle Research Laboratory
+//
+// This file is part of the omnithread library
+//
+// The omnithread library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free
+// Software Foundation, Inc., 51 Franklin Street, Boston, MA
+// 02110-1301, USA
+//
+// OMNI thread implementation classes for solaris threads.
+//
+
+#ifndef __omnithread_solaris_h_
+#define __omnithread_solaris_h_
+
+#include <thread.h>
+
+extern "C" void* omni_thread_wrapper(void* ptr);
+
+#define OMNI_MUTEX_IMPLEMENTATION \
+ mutex_t sol_mutex;
+
+#define OMNI_CONDITION_IMPLEMENTATION \
+ cond_t sol_cond;
+
+#define OMNI_SEMAPHORE_IMPLEMENTATION \
+ sema_t sol_sem;
+
+#define OMNI_THREAD_IMPLEMENTATION \
+ thread_t sol_thread; \
+ static int sol_priority(priority_t); \
+ friend void* omni_thread_wrapper(void* ptr);
+
+#endif
diff --git a/omnithread/posix.cc b/omnithread/posix.cc
new file mode 100644
index 000000000..b82e86df3
--- /dev/null
+++ b/omnithread/posix.cc
@@ -0,0 +1,972 @@
+// Package : omnithread
+// omnithread/posix.cc Created : 7/94 tjr
+//
+// Copyright (C) 2006 Free Software Foundation, Inc.
+// Copyright (C) 1994-1999 AT&T Laboratories Cambridge
+//
+// This file is part of the omnithread library
+//
+// The omnithread library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free
+// Software Foundation, Inc., 51 Franklin Street, Boston, MA
+// 02110-1301, USA
+//
+
+//
+// Implementation of OMNI thread abstraction for posix threads
+//
+// The source below tests for the definition of the macros:
+// PthreadDraftVersion
+// PthreadSupportThreadPriority
+// NoNanoSleep
+// NeedPthreadInit
+//
+// As different draft versions of the pthread standard P1003.4a/P1003.1c
+// define slightly different APIs, the macro 'PthreadDraftVersion'
+// identifies the draft version supported by this particular platform.
+//
+// Some unix variants do not support thread priority unless a real-time
+// kernel option is installed. The macro 'PthreadSupportThreadPriority',
+// if defined, enables the use of thread priority. If it is not defined,
+// setting or changing thread priority will be silently ignored.
+//
+// nanosleep() is defined in Posix P1003.4 since Draft 9 (?).
+// Not all platforms support this standard. The macro 'NoNanoSleep'
+// identifies platform that don't.
+//
+
+#include <config.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <time.h>
+#include <omnithread.h>
+
+#ifdef HAVE_NANOSLEEP
+#undef NoNanoSleep
+#else
+#define NoNanoSleep
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+// typedef of struct timeval and gettimeofday();
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+
+#if defined(__linux__) && defined(_MIT_POSIX_THREADS)
+#include <pthread/mit/sys/timers.h>
+#endif
+
+#if defined(__irix__) && defined(PthreadSupportThreadPriority)
+#if _POSIX_THREAD_PRIORITY_SCHEDULING
+#include <sched.h>
+#endif
+#endif
+
+#define DB(x) // x
+//#include <iostream.h> or #include <iostream> if DB is on.
+
+#if (PthreadDraftVersion <= 6)
+#define ERRNO(x) (((x) != 0) ? (errno) : 0)
+#ifdef __VMS
+// pthread_setprio returns old priority on success (draft version 4:
+// OpenVms version < 7)
+#define THROW_ERRORS(x) { if ((x) == -1) throw omni_thread_fatal(errno); }
+#else
+#define THROW_ERRORS(x) { if ((x) != 0) throw omni_thread_fatal(errno); }
+#endif
+#else
+#define ERRNO(x) (x)
+#define THROW_ERRORS(x) { int rc = (x); \
+ if (rc != 0) throw omni_thread_fatal(rc); }
+#endif
+
+
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Mutex
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+omni_mutex::omni_mutex(void)
+{
+#if (PthreadDraftVersion == 4)
+ THROW_ERRORS(pthread_mutex_init(&posix_mutex, pthread_mutexattr_default));
+#else
+ THROW_ERRORS(pthread_mutex_init(&posix_mutex, 0));
+#endif
+}
+
+omni_mutex::~omni_mutex(void)
+{
+ THROW_ERRORS(pthread_mutex_destroy(&posix_mutex));
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Condition variable
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+omni_condition::omni_condition(omni_mutex* m) : mutex(m)
+{
+#if (PthreadDraftVersion == 4)
+ THROW_ERRORS(pthread_cond_init(&posix_cond, pthread_condattr_default));
+#else
+ THROW_ERRORS(pthread_cond_init(&posix_cond, 0));
+#endif
+}
+
+omni_condition::~omni_condition(void)
+{
+ THROW_ERRORS(pthread_cond_destroy(&posix_cond));
+}
+
+void
+omni_condition::wait(void)
+{
+ THROW_ERRORS(pthread_cond_wait(&posix_cond, &mutex->posix_mutex));
+}
+
+int
+omni_condition::timedwait(unsigned long secs, unsigned long nanosecs)
+{
+ timespec rqts = { secs, nanosecs };
+
+again:
+ int rc = ERRNO(pthread_cond_timedwait(&posix_cond,
+ &mutex->posix_mutex, &rqts));
+ if (rc == 0)
+ return 1;
+
+#if (PthreadDraftVersion <= 6)
+ if (rc == EAGAIN)
+ return 0;
+#endif
+
+ // Some versions of unix produces this errno when the wait was
+ // interrupted by a unix signal or fork.
+ // Some versions of the glibc 2.0.x produces this errno when the
+ // program is debugged under gdb. Straightly speaking this is non-posix
+ // compliant. We catch this here to make debugging possible.
+ if (rc == EINTR)
+ goto again;
+
+ if (rc == ETIMEDOUT)
+ return 0;
+
+ throw omni_thread_fatal(rc);
+#ifdef _MSC_VER
+ return 0;
+#endif
+}
+
+void
+omni_condition::signal(void)
+{
+ THROW_ERRORS(pthread_cond_signal(&posix_cond));
+}
+
+void
+omni_condition::broadcast(void)
+{
+ THROW_ERRORS(pthread_cond_broadcast(&posix_cond));
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Counting (or binary) semaphore
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+omni_semaphore::omni_semaphore(unsigned int initial, unsigned int _max_count) : c(&m)
+{
+ value = initial;
+ max_count = _max_count;
+ if (value < 0 || max_count < 1)
+ throw omni_thread_fatal(0);
+}
+
+omni_semaphore::~omni_semaphore(void)
+{
+}
+
+void
+omni_semaphore::wait(void)
+{
+ omni_mutex_lock l(m);
+
+ while (value == 0)
+ c.wait();
+
+ value--;
+}
+
+int
+omni_semaphore::trywait(void)
+{
+ omni_mutex_lock l(m);
+
+ if (value == 0)
+ return 0;
+
+ value--;
+ return 1;
+}
+
+void
+omni_semaphore::post(void)
+{
+ {
+ omni_mutex_lock l(m);
+ if (value < max_count)
+ value++;
+ }
+
+ c.signal();
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Thread
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+//
+// static variables
+//
+
+omni_mutex* omni_thread::next_id_mutex;
+int omni_thread::next_id = 0;
+
+static pthread_key_t self_key;
+
+#ifdef PthreadSupportThreadPriority
+static int lowest_priority;
+static int normal_priority;
+static int highest_priority;
+#endif
+
+#if defined(__osf1__) && defined(__alpha__) || defined(__VMS)
+// omniORB requires a larger stack size than the default (21120) on OSF/1
+static size_t stack_size = 32768;
+#elif defined(__rtems__)
+static size_t stack_size = ThreadStackSize;
+#elif defined(__aix__)
+static size_t stack_size = 262144;
+#else
+static size_t stack_size = 0;
+#endif
+
+//
+// Initialisation function (gets called before any user code).
+//
+
+static int& count() {
+ static int the_count = 0;
+ return the_count;
+}
+
+omni_thread::init_t::init_t(void)
+{
+ if (count()++ != 0) // only do it once however many objects get created.
+ return;
+
+ DB(cerr << "omni_thread::init: posix 1003.4a/1003.1c (draft "
+ << PthreadDraftVersion << ") implementation initialising\n");
+
+#ifdef NeedPthreadInit
+
+ pthread_init();
+
+#endif
+
+#if (PthreadDraftVersion == 4)
+ THROW_ERRORS(pthread_keycreate(&self_key, NULL));
+#else
+ THROW_ERRORS(pthread_key_create(&self_key, NULL));
+#endif
+
+#ifdef PthreadSupportThreadPriority
+
+#if defined(__osf1__) && defined(__alpha__) || defined(__VMS)
+
+ lowest_priority = PRI_OTHER_MIN;
+ highest_priority = PRI_OTHER_MAX;
+
+#elif defined(__hpux__)
+
+ lowest_priority = PRI_OTHER_MIN;
+ highest_priority = PRI_OTHER_MAX;
+
+#elif defined(__sunos__) && (__OSVERSION__ == 5)
+
+ // a bug in pthread_attr_setschedparam means lowest priority is 1 not 0
+
+ lowest_priority = 1;
+ highest_priority = 3;
+
+#else
+
+ lowest_priority = sched_get_priority_min(SCHED_FIFO);
+ highest_priority = sched_get_priority_max(SCHED_FIFO);
+
+#endif
+
+ switch (highest_priority - lowest_priority) {
+
+ case 0:
+ case 1:
+ normal_priority = lowest_priority;
+ break;
+
+ default:
+ normal_priority = lowest_priority + 1;
+ break;
+ }
+
+#endif /* PthreadSupportThreadPriority */
+
+ next_id_mutex = new omni_mutex;
+
+ //
+ // Create object for this (i.e. initial) thread.
+ //
+
+ omni_thread* t = new omni_thread;
+
+ t->_state = STATE_RUNNING;
+
+ t->posix_thread = pthread_self ();
+
+ DB(cerr << "initial thread " << t->id() << endl);
+
+ THROW_ERRORS(pthread_setspecific(self_key, (void*)t));
+
+#ifdef PthreadSupportThreadPriority
+
+#if (PthreadDraftVersion == 4)
+
+ THROW_ERRORS(pthread_setprio(t->posix_thread,
+ posix_priority(PRIORITY_NORMAL)));
+
+#elif (PthreadDraftVersion == 6)
+
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+
+ THROW_ERRORS(pthread_attr_setprio(&attr, posix_priority(PRIORITY_NORMAL)));
+
+ THROW_ERRORS(pthread_setschedattr(t->posix_thread, attr));
+
+#else
+
+ struct sched_param sparam;
+
+ sparam.sched_priority = posix_priority(PRIORITY_NORMAL);
+
+ THROW_ERRORS(pthread_setschedparam(t->posix_thread, SCHED_OTHER, &sparam));
+
+#endif /* PthreadDraftVersion */
+
+#endif /* PthreadSupportThreadPriority */
+}
+
+omni_thread::init_t::~init_t(void)
+{
+ if (--count() != 0) return;
+
+ omni_thread* self = omni_thread::self();
+ if (!self) return;
+
+ pthread_setspecific(self_key, 0);
+ delete self;
+
+ delete next_id_mutex;
+}
+
+//
+// Wrapper for thread creation.
+//
+
+extern "C" void*
+omni_thread_wrapper(void* ptr)
+{
+ omni_thread* me = (omni_thread*)ptr;
+
+ DB(cerr << "omni_thread_wrapper: thread " << me->id()
+ << " started\n");
+
+ THROW_ERRORS(pthread_setspecific(self_key, me));
+
+ //
+ // Now invoke the thread function with the given argument.
+ //
+
+ if (me->fn_void != NULL) {
+ (*me->fn_void)(me->thread_arg);
+ omni_thread::exit();
+ }
+
+ if (me->fn_ret != NULL) {
+ void* return_value = (*me->fn_ret)(me->thread_arg);
+ omni_thread::exit(return_value);
+ }
+
+ if (me->detached) {
+ me->run(me->thread_arg);
+ omni_thread::exit();
+ } else {
+ void* return_value = me->run_undetached(me->thread_arg);
+ omni_thread::exit(return_value);
+ }
+
+ // should never get here.
+
+ return NULL;
+}
+
+
+//
+// Constructors for omni_thread - set up the thread object but don't
+// start it running.
+//
+
+// construct a detached thread running a given function.
+
+omni_thread::omni_thread(void (*fn)(void*), void* arg, priority_t pri)
+{
+ common_constructor(arg, pri, 1);
+ fn_void = fn;
+ fn_ret = NULL;
+}
+
+// construct an undetached thread running a given function.
+
+omni_thread::omni_thread(void* (*fn)(void*), void* arg, priority_t pri)
+{
+ common_constructor(arg, pri, 0);
+ fn_void = NULL;
+ fn_ret = fn;
+}
+
+// construct a thread which will run either run() or run_undetached().
+
+omni_thread::omni_thread(void* arg, priority_t pri)
+{
+ common_constructor(arg, pri, 1);
+ fn_void = NULL;
+ fn_ret = NULL;
+}
+
+// common part of all constructors.
+
+void
+omni_thread::common_constructor(void* arg, priority_t pri, int det)
+{
+ _state = STATE_NEW;
+ _priority = pri;
+
+ next_id_mutex->lock();
+ _id = next_id++;
+ next_id_mutex->unlock();
+
+ thread_arg = arg;
+ detached = det; // may be altered in start_undetached()
+
+ _dummy = 0;
+ _values = 0;
+ _value_alloc = 0;
+ // posix_thread is set up in initialisation routine or start().
+}
+
+
+//
+// Destructor for omni_thread.
+//
+
+omni_thread::~omni_thread(void)
+{
+ DB(cerr << "destructor called for thread " << id() << endl);
+ if (_values) {
+ for (key_t i=0; i < _value_alloc; i++) {
+ if (_values[i]) {
+ delete _values[i];
+ }
+ }
+ delete [] _values;
+ }
+}
+
+
+//
+// Start the thread
+//
+
+void
+omni_thread::start(void)
+{
+ omni_mutex_lock l(mutex);
+
+ if (_state != STATE_NEW)
+ throw omni_thread_invalid();
+
+ pthread_attr_t attr;
+
+#if (PthreadDraftVersion == 4)
+ pthread_attr_create(&attr);
+#else
+ pthread_attr_init(&attr);
+#endif
+
+#if (PthreadDraftVersion == 8)
+ pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_UNDETACHED);
+#endif
+
+#ifdef PthreadSupportThreadPriority
+
+#if (PthreadDraftVersion <= 6)
+
+ THROW_ERRORS(pthread_attr_setprio(&attr, posix_priority(_priority)));
+
+#else
+
+ struct sched_param sparam;
+
+ sparam.sched_priority = posix_priority(_priority);
+
+ THROW_ERRORS(pthread_attr_setschedparam(&attr, &sparam));
+
+#endif /* PthreadDraftVersion */
+
+#endif /* PthreadSupportThreadPriority */
+
+#if !defined(__linux__)
+ if (stack_size) {
+ THROW_ERRORS(pthread_attr_setstacksize(&attr, stack_size));
+ }
+#endif
+
+
+#if (PthreadDraftVersion == 4)
+ THROW_ERRORS(pthread_create(&posix_thread, attr, omni_thread_wrapper,
+ (void*)this));
+ pthread_attr_delete(&attr);
+#else
+ THROW_ERRORS(pthread_create(&posix_thread, &attr, omni_thread_wrapper,
+ (void*)this));
+ pthread_attr_destroy(&attr);
+#endif
+
+ _state = STATE_RUNNING;
+
+ if (detached) {
+
+#if (PthreadDraftVersion <= 6)
+ THROW_ERRORS(pthread_detach(&posix_thread));
+#else
+ THROW_ERRORS(pthread_detach(posix_thread));
+#endif
+ }
+}
+
+
+//
+// Start a thread which will run the member function run_undetached().
+//
+
+void
+omni_thread::start_undetached(void)
+{
+ if ((fn_void != NULL) || (fn_ret != NULL))
+ throw omni_thread_invalid();
+
+ detached = 0;
+ start();
+}
+
+
+//
+// join - simply check error conditions & call pthread_join.
+//
+
+void
+omni_thread::join(void** status)
+{
+ mutex.lock();
+
+ if ((_state != STATE_RUNNING) && (_state != STATE_TERMINATED)) {
+ mutex.unlock();
+ throw omni_thread_invalid();
+ }
+
+ mutex.unlock();
+
+ if (this == self())
+ throw omni_thread_invalid();
+
+ if (detached)
+ throw omni_thread_invalid();
+
+ DB(cerr << "omni_thread::join: doing pthread_join\n");
+
+ THROW_ERRORS(pthread_join(posix_thread, status));
+
+ DB(cerr << "omni_thread::join: pthread_join succeeded\n");
+
+#if (PthreadDraftVersion == 4)
+ // With draft 4 pthreads implementations (HPUX 10.x and
+ // Digital Unix 3.2), have to detach the thread after
+ // join. If not, the storage for the thread will not be
+ // be reclaimed.
+ THROW_ERRORS(pthread_detach(&posix_thread));
+#endif
+
+ delete this;
+}
+
+
+//
+// Change this thread's priority.
+//
+
+void
+omni_thread::set_priority(priority_t pri)
+{
+ omni_mutex_lock l(mutex);
+
+ if (_state != STATE_RUNNING)
+ throw omni_thread_invalid();
+
+ _priority = pri;
+
+#ifdef PthreadSupportThreadPriority
+
+#if (PthreadDraftVersion == 4)
+
+ THROW_ERRORS(pthread_setprio(posix_thread, posix_priority(pri)));
+
+#elif (PthreadDraftVersion == 6)
+
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+
+ THROW_ERRORS(pthread_attr_setprio(&attr, posix_priority(pri)));
+
+ THROW_ERRORS(pthread_setschedattr(posix_thread, attr));
+
+#else
+
+ struct sched_param sparam;
+
+ sparam.sched_priority = posix_priority(pri);
+
+ THROW_ERRORS(pthread_setschedparam(posix_thread, SCHED_OTHER, &sparam));
+
+#endif /* PthreadDraftVersion */
+
+#endif /* PthreadSupportThreadPriority */
+}
+
+
+//
+// create - construct a new thread object and start it running. Returns thread
+// object if successful, null pointer if not.
+//
+
+// detached version
+
+omni_thread*
+omni_thread::create(void (*fn)(void*), void* arg, priority_t pri)
+{
+ omni_thread* t = new omni_thread(fn, arg, pri);
+
+ t->start();
+
+ return t;
+}
+
+// undetached version
+
+omni_thread*
+omni_thread::create(void* (*fn)(void*), void* arg, priority_t pri)
+{
+ omni_thread* t = new omni_thread(fn, arg, pri);
+
+ t->start();
+
+ return t;
+}
+
+
+//
+// exit() _must_ lock the mutex even in the case of a detached thread. This is
+// because a thread may run to completion before the thread that created it has
+// had a chance to get out of start(). By locking the mutex we ensure that the
+// creating thread must have reached the end of start() before we delete the
+// thread object. Of course, once the call to start() returns, the user can
+// still incorrectly refer to the thread object, but that's their problem.
+//
+
+void
+omni_thread::exit(void* return_value)
+{
+ omni_thread* me = self();
+
+ if (me)
+ {
+ me->mutex.lock();
+
+ me->_state = STATE_TERMINATED;
+
+ me->mutex.unlock();
+
+ DB(cerr << "omni_thread::exit: thread " << me->id() << " detached "
+ << me->detached << " return value " << return_value << endl);
+
+ if (me->detached)
+ delete me;
+ }
+ else
+ {
+ DB(cerr << "omni_thread::exit: called with a non-omnithread. Exit quietly." << endl);
+ }
+
+ pthread_exit(return_value);
+}
+
+
+omni_thread*
+omni_thread::self(void)
+{
+ omni_thread* me;
+
+#if (PthreadDraftVersion <= 6)
+
+ THROW_ERRORS(pthread_getspecific(self_key, (void**)&me));
+
+#else
+
+ me = (omni_thread *)pthread_getspecific(self_key);
+
+#endif
+
+ if (!me) {
+ // This thread is not created by omni_thread::start because it
+ // doesn't has a class omni_thread instance attached to its key.
+ DB(cerr << "omni_thread::self: called with a non-omnithread. NULL is returned." << endl);
+ }
+
+ return me;
+}
+
+
+void
+omni_thread::yield(void)
+{
+#if (PthreadDraftVersion == 6)
+
+ pthread_yield(NULL);
+
+#elif (PthreadDraftVersion < 9)
+
+ pthread_yield();
+
+#else
+
+ THROW_ERRORS(sched_yield());
+
+#endif
+}
+
+
+void
+omni_thread::sleep(unsigned long secs, unsigned long nanosecs)
+{
+ timespec rqts = { secs, nanosecs };
+
+#ifndef NoNanoSleep
+
+ timespec remain;
+ while (nanosleep(&rqts, &remain)) {
+ if (errno == EINTR) {
+ rqts.tv_sec = remain.tv_sec;
+ rqts.tv_nsec = remain.tv_nsec;
+ continue;
+ }
+ else
+ throw omni_thread_fatal(errno);
+ }
+#else
+
+#if defined(__osf1__) && defined(__alpha__) || defined(__hpux__) && (__OSVERSION__ == 10) || defined(__VMS) || defined(__SINIX__) || defined (__POSIX_NT__)
+
+ if (pthread_delay_np(&rqts) != 0)
+ throw omni_thread_fatal(errno);
+
+#elif defined(__linux__) || defined(__aix__)
+
+ if (secs > 2000) {
+ while ((secs = ::sleep(secs))) ;
+ } else {
+ usleep(secs * 1000000 + (nanosecs / 1000));
+ }
+
+#elif defined(__darwin__) || defined(__macos__)
+
+ // Single UNIX Specification says argument of usleep() must be
+ // less than 1,000,000.
+ secs += nanosecs / 1000000000;
+ nanosecs %= 1000000000;
+ while ((secs = ::sleep(secs))) ;
+ usleep(nanosecs / 1000);
+
+#else
+
+ throw omni_thread_invalid();
+
+#endif
+#endif /* NoNanoSleep */
+}
+
+
+void
+omni_thread::get_time(unsigned long* abs_sec, unsigned long* abs_nsec,
+ unsigned long rel_sec, unsigned long rel_nsec)
+{
+ timespec abs;
+
+#if defined(__osf1__) && defined(__alpha__) || defined(__hpux__) && (__OSVERSION__ == 10) || defined(__VMS) || defined(__SINIX__) || defined(__POSIX_NT__)
+
+ timespec rel;
+ rel.tv_sec = rel_sec;
+ rel.tv_nsec = rel_nsec;
+ THROW_ERRORS(pthread_get_expiration_np(&rel, &abs));
+
+#else
+
+#ifdef HAVE_CLOCK_GETTIME /* __linux__ || __aix__ */
+
+ clock_gettime(CLOCK_REALTIME, &abs);
+
+#elif defined(HAVE_GETTIMEOFDAY) /* defined(__linux__) || defined(__aix__) || defined(__SCO_VERSION__) || defined(__darwin__) || defined(__macos__) */
+
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ abs.tv_sec = tv.tv_sec;
+ abs.tv_nsec = tv.tv_usec * 1000;
+
+#else
+#error no get time support
+#endif /* __linux__ || __aix__ */
+
+ abs.tv_nsec += rel_nsec;
+ abs.tv_sec += rel_sec + abs.tv_nsec / 1000000000;
+ abs.tv_nsec = abs.tv_nsec % 1000000000;
+
+#endif /* __osf1__ && __alpha__ */
+
+ *abs_sec = abs.tv_sec;
+ *abs_nsec = abs.tv_nsec;
+}
+
+
+int
+omni_thread::posix_priority(priority_t pri)
+{
+#ifdef PthreadSupportThreadPriority
+ switch (pri) {
+
+ case PRIORITY_LOW:
+ return lowest_priority;
+
+ case PRIORITY_NORMAL:
+ return normal_priority;
+
+ case PRIORITY_HIGH:
+ return highest_priority;
+
+ }
+#endif
+
+ throw omni_thread_invalid();
+#ifdef _MSC_VER
+ return 0;
+#endif
+}
+
+void
+omni_thread::stacksize(unsigned long sz)
+{
+ stack_size = sz;
+}
+
+unsigned long
+omni_thread::stacksize()
+{
+ return stack_size;
+}
+
+//
+// Dummy thread
+//
+
+class omni_thread_dummy : public omni_thread {
+public:
+ inline omni_thread_dummy() : omni_thread()
+ {
+ _dummy = 1;
+ _state = STATE_RUNNING;
+ posix_thread = pthread_self();
+ THROW_ERRORS(pthread_setspecific(self_key, (void*)this));
+ }
+ inline ~omni_thread_dummy()
+ {
+ THROW_ERRORS(pthread_setspecific(self_key, 0));
+ }
+};
+
+omni_thread*
+omni_thread::create_dummy()
+{
+ if (omni_thread::self())
+ throw omni_thread_invalid();
+
+ return new omni_thread_dummy;
+}
+
+void
+omni_thread::release_dummy()
+{
+ omni_thread* self = omni_thread::self();
+ if (!self || !self->_dummy)
+ throw omni_thread_invalid();
+
+ omni_thread_dummy* dummy = (omni_thread_dummy*)self;
+ delete dummy;
+}
+
+
+#define INSIDE_THREAD_IMPL_CC
+#include "threaddata.cc"
+#undef INSIDE_THREAD_IMPL_CC
diff --git a/omnithread/solaris.cc b/omnithread/solaris.cc
new file mode 100644
index 000000000..b0139d29d
--- /dev/null
+++ b/omnithread/solaris.cc
@@ -0,0 +1,615 @@
+// Package : omnithread
+// omnithread/solaris.cc Created : 7/94 tjr
+//
+// Copyright (C) 1994-1999 AT&T Laboratories Cambridge
+//
+// This file is part of the omnithread library
+//
+// The omnithread library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free
+// Software Foundation, Inc., 51 Franklin Street, Boston, MA
+// 02110-1301, USA
+//
+//
+// Implementation of OMNI thread abstraction for solaris threads.
+//
+
+#include <stdlib.h>
+#include <errno.h>
+#include <omnithread.h>
+
+#define DB(x) // x
+// #include <iostream> or #include <iostream.h> if DB is on.
+
+#define THROW_ERRORS(x) { int rc = (x); \
+ if (rc != 0) throw omni_thread_fatal(rc); }
+
+
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Mutex
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+omni_mutex::omni_mutex(void)
+{
+ THROW_ERRORS(mutex_init(&sol_mutex, USYNC_THREAD, 0));
+}
+
+omni_mutex::~omni_mutex(void)
+{
+ THROW_ERRORS(mutex_destroy(&sol_mutex));
+}
+
+void
+omni_mutex::lock(void)
+{
+ THROW_ERRORS(mutex_lock(&sol_mutex));
+}
+
+void
+omni_mutex::unlock(void)
+{
+ THROW_ERRORS(mutex_unlock(&sol_mutex));
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Condition variable
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+omni_condition::omni_condition(omni_mutex* m) : mutex(m)
+{
+ THROW_ERRORS(cond_init(&sol_cond, USYNC_THREAD, 0));
+}
+
+omni_condition::~omni_condition(void)
+{
+ THROW_ERRORS(cond_destroy(&sol_cond));
+}
+
+void
+omni_condition::wait(void)
+{
+ THROW_ERRORS(cond_wait(&sol_cond, &mutex->sol_mutex));
+}
+
+int
+omni_condition::timedwait(unsigned long secs, unsigned long nanosecs)
+{
+ timespec rqts = { secs, nanosecs };
+
+ again:
+ int rc = cond_timedwait(&sol_cond, &mutex->sol_mutex, &rqts);
+
+ if (rc == 0)
+ return 1;
+
+ if (rc == EINTR)
+ goto again;
+
+ if (rc == ETIME)
+ return 0;
+
+ throw omni_thread_fatal(rc);
+}
+
+void
+omni_condition::signal(void)
+{
+ THROW_ERRORS(cond_signal(&sol_cond));
+}
+
+void
+omni_condition::broadcast(void)
+{
+ THROW_ERRORS(cond_broadcast(&sol_cond));
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Counting semaphore
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+omni_semaphore::omni_semaphore(unsigned int initial)
+{
+ THROW_ERRORS(sema_init(&sol_sem, initial, USYNC_THREAD, NULL));
+}
+
+omni_semaphore::~omni_semaphore(void)
+{
+ THROW_ERRORS(sema_destroy(&sol_sem));
+}
+
+void
+omni_semaphore::wait(void)
+{
+ THROW_ERRORS(sema_wait(&sol_sem));
+}
+
+void
+omni_semaphore::post(void)
+{
+ THROW_ERRORS(sema_post(&sol_sem));
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Thread
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+//
+// Static variables
+//
+
+int omni_thread::init_t::count = 0;
+
+omni_mutex* omni_thread::next_id_mutex;
+int omni_thread::next_id = 0;
+
+static thread_key_t self_key;
+
+static size_t stack_size = 0;
+
+//
+// Initialisation function (gets called before any user code).
+//
+
+omni_thread::init_t::init_t(void)
+{
+ if (count++ != 0) // only do it once however many objects get created.
+ return;
+
+ DB(cerr << "omni_thread::init: solaris implementation initialising\n");
+
+ THROW_ERRORS(thr_keycreate(&self_key, NULL));
+
+ next_id_mutex = new omni_mutex;
+
+ //
+ // Create object for this (i.e. initial) thread.
+ //
+
+ omni_thread* t = new omni_thread;
+
+ t->_state = STATE_RUNNING;
+
+ t->sol_thread = thr_self();
+
+ DB(cerr << "initial thread " << t->id() << " sol_thread " << t->sol_thread
+ << endl);
+
+ THROW_ERRORS(thr_setspecific(self_key, (void*)t));
+
+ THROW_ERRORS(thr_setprio(t->sol_thread, sol_priority(PRIORITY_NORMAL)));
+}
+
+
+//
+// Wrapper for thread creation.
+//
+
+extern "C" void*
+omni_thread_wrapper(void* ptr)
+{
+ omni_thread* me = (omni_thread*)ptr;
+
+ DB(cerr << "omni_thread::wrapper: thread " << me->id()
+ << " started\n");
+
+ THROW_ERRORS(thr_setspecific(self_key, me));
+
+ //
+ // Now invoke the thread function with the given argument.
+ //
+
+ if (me->fn_void != NULL) {
+ (*me->fn_void)(me->thread_arg);
+ omni_thread::exit();
+ }
+
+ if (me->fn_ret != NULL) {
+ void* return_value = (*me->fn_ret)(me->thread_arg);
+ omni_thread::exit(return_value);
+ }
+
+ if (me->detached) {
+ me->run(me->thread_arg);
+ omni_thread::exit();
+ } else {
+ void* return_value = me->run_undetached(me->thread_arg);
+ omni_thread::exit(return_value);
+ }
+
+ // should never get here.
+
+ return NULL;
+}
+
+
+//
+// Constructors for omni_thread - set up the thread object but don't
+// start it running.
+//
+
+// construct a detached thread running a given function.
+
+omni_thread::omni_thread(void (*fn)(void*), void* arg, priority_t pri)
+{
+ common_constructor(arg, pri, 1);
+ fn_void = fn;
+ fn_ret = NULL;
+}
+
+// construct an undetached thread running a given function.
+
+omni_thread::omni_thread(void* (*fn)(void*), void* arg, priority_t pri)
+{
+ common_constructor(arg, pri, 0);
+ fn_void = NULL;
+ fn_ret = fn;
+}
+
+// construct a thread which will run either run() or run_undetached().
+
+omni_thread::omni_thread(void* arg, priority_t pri)
+{
+ common_constructor(arg, pri, 1);
+ fn_void = NULL;
+ fn_ret = NULL;
+}
+
+// common part of all constructors.
+
+void
+omni_thread::common_constructor(void* arg, priority_t pri, int det)
+{
+ _state = STATE_NEW;
+ _priority = pri;
+
+ next_id_mutex->lock();
+ _id = next_id++;
+ next_id_mutex->unlock();
+
+ thread_arg = arg;
+ detached = det; // may be altered in start_undetached()
+
+ _dummy = 0;
+ _values = 0;
+ _value_alloc = 0;
+ // sol_thread is set up in initialisation routine or start().
+}
+
+
+//
+// Destructor for omni_thread.
+//
+
+omni_thread::~omni_thread(void)
+{
+ DB(cerr << "destructor called for thread " << id() << endl);
+ if (_values) {
+ for (key_t i=0; i < _value_alloc; i++) {
+ if (_values[i]) {
+ delete _values[i];
+ }
+ }
+ delete [] _values;
+ }
+}
+
+
+//
+// Start the thread
+//
+
+void
+omni_thread::start(void)
+{
+ long flags = 0;
+
+ if (detached)
+ flags |= THR_DETACHED;
+
+ omni_mutex_lock l(mutex);
+
+ if (_state != STATE_NEW)
+ throw omni_thread_invalid();
+
+ THROW_ERRORS(thr_create(0, stack_size, omni_thread_wrapper, (void*)this, flags,
+ &sol_thread));
+
+ _state = STATE_RUNNING;
+
+ THROW_ERRORS(thr_setprio(sol_thread, sol_priority(_priority)));
+}
+
+
+//
+// Start a thread which will run the member function run_undetached().
+//
+
+void
+omni_thread::start_undetached(void)
+{
+ if ((fn_void != NULL) || (fn_ret != NULL))
+ throw omni_thread_invalid();
+
+ detached = 0;
+ start();
+}
+
+
+//
+// join - simply check error conditions & call thr_join.
+//
+
+void
+omni_thread::join(void** status)
+{
+ mutex.lock();
+
+ if ((_state != STATE_RUNNING) && (_state != STATE_TERMINATED)) {
+ mutex.unlock();
+ throw omni_thread_invalid();
+ }
+
+ mutex.unlock();
+
+ if (this == self())
+ throw omni_thread_invalid();
+
+ if (detached)
+ throw omni_thread_invalid();
+
+ DB(cerr << "omni_thread::join: doing thr_join\n");
+
+ THROW_ERRORS(thr_join(sol_thread, (thread_t *)NULL, status));
+
+ DB(cerr << "omni_thread::join: thr_join succeeded\n");
+
+ delete this;
+}
+
+
+//
+// Change this thread's priority.
+//
+
+void
+omni_thread::set_priority(priority_t pri)
+{
+ omni_mutex_lock l(mutex);
+
+ if (_state != STATE_RUNNING)
+ throw omni_thread_invalid();
+
+ _priority = pri;
+
+ THROW_ERRORS(thr_setprio(sol_thread, sol_priority(pri)));
+}
+
+
+//
+// create - construct a new thread object and start it running. Returns thread
+// object if successful, null pointer if not.
+//
+
+// detached version
+
+omni_thread*
+omni_thread::create(void (*fn)(void*), void* arg, priority_t pri)
+{
+ omni_thread* t = new omni_thread(fn, arg, pri);
+
+ t->start();
+
+ return t;
+}
+
+// undetached version
+
+omni_thread*
+omni_thread::create(void* (*fn)(void*), void* arg, priority_t pri)
+{
+ omni_thread* t = new omni_thread(fn, arg, pri);
+
+ t->start();
+
+ return t;
+}
+
+
+//
+// exit() _must_ lock the mutex even in the case of a detached thread. This is
+// because a thread may run to completion before the thread that created it has
+// had a chance to get out of start(). By locking the mutex we ensure that the
+// creating thread must have reached the end of start() before we delete the
+// thread object. Of course, once the call to start() returns, the user can
+// still incorrectly refer to the thread object, but that's their problem.
+//
+
+void
+omni_thread::exit(void* return_value)
+{
+ omni_thread* me = self();
+
+ if (me)
+ {
+ me->mutex.lock();
+
+ me->_state = STATE_TERMINATED;
+
+ me->mutex.unlock();
+
+ DB(cerr << "omni_thread::exit: thread " << me->id() << " detached "
+ << me->detached << " return value " << return_value << endl);
+
+ if (me->detached)
+ delete me;
+ }
+ else
+ {
+ DB(cerr << "omni_thread::exit: called with a non-omnithread. Exit quietly." << endl);
+ }
+
+ thr_exit(return_value);
+}
+
+
+omni_thread*
+omni_thread::self(void)
+{
+ omni_thread* me;
+
+ THROW_ERRORS(thr_getspecific(self_key, (void**)&me));
+
+ if (!me) {
+ // This thread is not created by omni_thread::start because it
+ // doesn't has a class omni_thread instance attached to its key.
+ DB(cerr << "omni_thread::self: called with a non-ominthread. NULL is returned." << endl);
+ }
+
+ return me;
+}
+
+
+void
+omni_thread::yield(void)
+{
+ thr_yield();
+}
+
+
+void
+omni_thread::sleep(unsigned long secs, unsigned long nanosecs)
+{
+ timespec rqts = { secs, nanosecs };
+ timespec remain;
+ while (nanosleep(&rqts, &remain)) {
+ if (errno == EINTR) {
+ rqts.tv_sec = remain.tv_sec;
+ rqts.tv_nsec = remain.tv_nsec;
+ continue;
+ }
+ else
+ throw omni_thread_fatal(errno);
+ }
+}
+
+
+void
+omni_thread::get_time(unsigned long* abs_sec, unsigned long* abs_nsec,
+ unsigned long rel_sec, unsigned long rel_nsec)
+{
+ timespec abs;
+ clock_gettime(CLOCK_REALTIME, &abs);
+ abs.tv_nsec += rel_nsec;
+ abs.tv_sec += rel_sec + abs.tv_nsec / 1000000000;
+ abs.tv_nsec = abs.tv_nsec % 1000000000;
+ *abs_sec = abs.tv_sec;
+ *abs_nsec = abs.tv_nsec;
+}
+
+
+int
+omni_thread::sol_priority(priority_t pri)
+{
+ switch (pri) {
+
+ case PRIORITY_LOW:
+ return 0;
+
+ case PRIORITY_NORMAL:
+ return 1;
+
+ case PRIORITY_HIGH:
+ return 2;
+ }
+
+ throw omni_thread_invalid();
+}
+
+
+void
+omni_thread::stacksize(unsigned long sz)
+{
+ stack_size = sz;
+}
+
+unsigned long
+omni_thread::stacksize()
+{
+ return stack_size;
+}
+
+
+//
+// Dummy thread
+//
+
+#error This dummy thread code is not tested. It might work if you're lucky.
+
+class omni_thread_dummy : public omni_thread {
+public:
+ inline omni_thread_dummy() : omni_thread()
+ {
+ _dummy = 1;
+ _state = STATE_RUNNING;
+ sol_thread = thr_self();
+ THROW_ERRORS(thr_setspecific(self_key, (void*)this));
+ }
+ inline ~omni_thread_dummy()
+ {
+ THROW_ERRORS(thr_setspecific(self_key, 0));
+ }
+};
+
+omni_thread*
+omni_thread::create_dummy()
+{
+ if (omni_thread::self())
+ throw omni_thread_invalid();
+
+ return new omni_thread_dummy;
+}
+
+void
+omni_thread::release_dummy()
+{
+ omni_thread* self = omni_thread::self();
+ if (!self || !self->_dummy)
+ throw omni_thread_invalid();
+
+ omni_thread_dummy* dummy = (omni_thread_dummy*)self;
+ delete dummy;
+}
+
+
+#define INSIDE_THREAD_IMPL_CC
+#include "threaddata.cc"
+#undef INSIDE_THREAD_IMPL_CC
diff --git a/omnithread/threaddata.cc b/omnithread/threaddata.cc
new file mode 100644
index 000000000..d54c43914
--- /dev/null
+++ b/omnithread/threaddata.cc
@@ -0,0 +1,83 @@
+// Package : omnithread
+// omnithread/threaddata.cc Created : 10/2000 dpg1
+//
+// Copyright (C) 2000 AT&T Laboratories Cambridge
+//
+// This file is part of the omnithread library
+//
+// The omnithread library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free
+// Software Foundation, Inc., 51 Franklin Street, Boston, MA
+// 02110-1301, USA
+//
+
+// Implementation of per-thread data
+
+#ifndef INSIDE_THREAD_IMPL_CC
+#error "threaddata.cc must be #included by a thread implementation."
+#endif
+
+
+static omni_thread::key_t allocated_keys = 0;
+
+omni_thread::key_t
+omni_thread::allocate_key()
+{
+ omni_mutex_lock l(*next_id_mutex);
+ return ++allocated_keys;
+}
+
+omni_thread::value_t*
+omni_thread::set_value(key_t k, value_t* v)
+{
+ if (k == 0) return 0;
+ if (k > _value_alloc) {
+ next_id_mutex->lock();
+ key_t alloc = allocated_keys;
+ next_id_mutex->unlock();
+
+ if (k > alloc) return 0;
+
+ value_t** nv = new value_t*[alloc];
+ key_t i = 0;
+ if (_values) {
+ for (; i < _value_alloc; i++)
+ nv[i] = _values[i];
+ delete [] _values;
+ }
+ for (; i < alloc; i++)
+ nv[i] = 0;
+
+ _values = nv;
+ _value_alloc = alloc;
+ }
+ if (_values[k-1]) delete _values[k-1];
+ _values[k-1] = v;
+ return v;
+}
+
+omni_thread::value_t*
+omni_thread::get_value(key_t k)
+{
+ if (k > _value_alloc) return 0;
+ return _values[k-1];
+}
+
+omni_thread::value_t*
+omni_thread::remove_value(key_t k)
+{
+ if (k > _value_alloc) return 0;
+ value_t* v = _values[k-1];
+ _values[k-1] = 0;
+ return v;
+}
diff --git a/omnithread/vxWorks.cc b/omnithread/vxWorks.cc
new file mode 100644
index 000000000..25634ce93
--- /dev/null
+++ b/omnithread/vxWorks.cc
@@ -0,0 +1,1160 @@
+//////////////////////////////////////////////////////////////////////////////
+// Filename: vxWorks.cc
+// Author: Tihomir Sokcevic
+// Acterna, Eningen.
+// Description: vxWorks adaptation of the omnithread wrapper classes
+// Notes: Munching strategy is imperative
+//////////////////////////////////////////////////////////////////////////////
+// $Log$
+// Revision 1.1 2004/04/10 18:00:52 eb
+// Initial revision
+//
+// Revision 1.1.1.1 2004/03/01 00:20:27 eb
+// initial checkin
+//
+// Revision 1.1 2003/05/25 05:29:04 eb
+// see ChangeLog
+//
+// Revision 1.1.2.1 2003/02/17 02:03:11 dgrisby
+// vxWorks port. (Thanks Michael Sturm / Acterna Eningen GmbH).
+//
+// Revision 1.1.1.1 2002/11/19 14:58:04 sokcevti
+// OmniOrb4.0.0 VxWorks port
+//
+// Revision 1.4 2002/10/15 07:54:09 kuttlest
+// change semaphore from SEM_FIFO to SEM_PRIO
+// ---
+//
+// Revision 1.3 2002/07/05 07:38:52 engeln
+// made priority redefinable on load time by defining int variables
+// omni_thread_prio_low = 220;
+// omni_thread_prio_normal = 110;
+// omni_thread_prio_high = 55;
+// the default priority is prio_normal.
+// The normal priority default has been increased from 200 to 110 and the
+// high priority from 100 to 55.
+// ---
+//
+// Revision 1.2 2002/06/14 12:44:57 engeln
+// replaced possibly unsafe wakeup procedure in broadcast.
+// ---
+//
+// Revision 1.1.1.1 2002/04/02 10:09:34 sokcevti
+// omniORB4 initial realease
+//
+// Revision 1.0 2001/10/23 14:22:45 sokcevti
+// Initial Version 4.00
+// ---
+//
+//////////////////////////////////////////////////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Include files
+//////////////////////////////////////////////////////////////////////////////
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <time.h>
+#include <omnithread.h>
+#include <sysLib.h>
+
+#include <assert.h> // assert
+#include <intLib.h> // intContext
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Local defines
+//////////////////////////////////////////////////////////////////////////////
+#define ERRNO(x) (((x) != 0) ? (errno) : 0)
+#define THROW_ERRORS(x) { if((x) != OK) throw omni_thread_fatal(errno); }
+#define OMNI_THREAD_ID 0x7F7155AAl
+#define OMNI_STACK_SIZE 32768l
+
+#ifdef _DEBUG
+ #include <fstream>
+ #define DBG_TRACE(X) X
+#else // _DEBUG
+ #define DBG_TRACE(X)
+#endif // _DEBUG
+
+#define DBG_ASSERT(X)
+
+#define DBG_THROW(X) X
+
+int omni_thread_prio_low = 220;
+int omni_thread_prio_normal = 110;
+int omni_thread_prio_high = 55;
+///////////////////////////////////////////////////////////////////////////
+//
+// Mutex
+//
+///////////////////////////////////////////////////////////////////////////
+omni_mutex::omni_mutex(void):m_bConstructed(false)
+{
+ mutexID = semMCreate(SEM_Q_PRIORITY | SEM_INVERSION_SAFE);
+
+ DBG_ASSERT(assert(mutexID != NULL));
+
+ if(mutexID==NULL)
+ {
+ DBG_TRACE(cout<<"Exception: omni_mutex::omni_mutex() tid: "<<(int)taskIdSelf()<<endl);
+ DBG_THROW(throw omni_thread_fatal(-1));
+ }
+
+ m_bConstructed = true;
+}
+
+omni_mutex::~omni_mutex(void)
+{
+ m_bConstructed = false;
+
+ STATUS status = semDelete(mutexID);
+
+ DBG_ASSERT(assert(status == OK));
+
+ if(status != OK)
+ {
+ DBG_TRACE(cout<<"Exception: omni_mutex::~omni_mutex() mutexID: "<<(int)mutexID<<" tid: "<<(int)taskIdSelf()<<endl);
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+}
+
+/*
+void omni_mutex::lock(void)
+{
+ DBG_ASSERT(assert(!intContext())); // not in ISR context
+ DBG_ASSERT(assert(m_bConstructed));
+
+ STATUS status = semTake(mutexID, WAIT_FOREVER);
+
+ DBG_ASSERT(assert(status == OK));
+
+ if(status != OK)
+ {
+ DBG_TRACE(cout<<"Exception: omni_mutex::lock() mutexID: "<<(int)mutexID<<" tid: "<<(int)taskIdSelf()<<endl);
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+}
+
+void omni_mutex::unlock(void)
+{
+ DBG_ASSERT(assert(m_bConstructed));
+
+ STATUS status = semGive(mutexID);
+
+ DBG_ASSERT(assert(status == OK));
+
+ if(status != OK)
+ {
+ DBG_TRACE(cout<<"Exception: omni_mutex::unlock() mutexID: "<<(int)mutexID<<" tid: "<<(int)taskIdSelf()<<endl);
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+}
+*/
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Condition variable
+//
+///////////////////////////////////////////////////////////////////////////
+omni_condition::omni_condition(omni_mutex* m) : mutex(m)
+{
+ DBG_TRACE(cout<<"omni_condition::omni_condition mutexID: "<<(int)mutex->mutexID<<" tid:"<<(int)taskIdSelf()<<endl);
+
+ waiters_ = 0;
+
+ sema_ = semCCreate(SEM_Q_PRIORITY, 0);
+ if(sema_ == NULL)
+ {
+ DBG_TRACE(cout<<"Exception: omni_condition::omni_condition() tid: "<<(int)taskIdSelf()<<endl);
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+
+ waiters_lock_ = semMCreate(SEM_Q_PRIORITY | SEM_INVERSION_SAFE);
+ if(waiters_lock_ == NULL)
+ {
+ DBG_TRACE(cout<<"Exception: omni_condition::omni_condition() tid: "<<(int)taskIdSelf()<<endl);
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+
+}
+
+omni_condition::~omni_condition(void)
+{
+ STATUS status = semDelete(waiters_lock_);
+
+ DBG_ASSERT(assert(status == OK));
+
+ if(status != OK)
+ {
+ DBG_TRACE(cout<<"Exception: omni_condition::~omni_condition"<<endl);
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+
+ status = semDelete(sema_);
+
+ DBG_ASSERT(assert(status == OK));
+
+ if(status != OK)
+ {
+ DBG_TRACE(cout<<"Exception: omni_condition::~omni_condition"<<endl);
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+}
+
+void omni_condition::wait(void)
+{
+ DBG_TRACE(cout<<"omni_condition::wait mutexID: "<<(int)mutex->mutexID<<" tid:"<<(int)taskIdSelf()<<endl);
+
+ // Prevent race conditions on the <waiters_> count.
+
+ STATUS status = semTake(waiters_lock_,WAIT_FOREVER);
+
+ DBG_ASSERT(assert(status == OK));
+
+ if(status != OK)
+ {
+ DBG_TRACE(cout<<"Exception: omni_condition::wait"<<endl);
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+
+ ++waiters_;
+
+ status = semGive(waiters_lock_);
+
+ DBG_ASSERT(assert(status == OK));
+
+ if(status != OK)
+ {
+ DBG_TRACE(cout<<"Exception: omni_condition::wait"<<endl);
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+
+ // disable task lock to have an atomic unlock+semTake
+ taskLock();
+
+ // We keep the lock held just long enough to increment the count of
+ // waiters by one. Note that we can't keep it held across the call
+ // to wait() since that will deadlock other calls to signal().
+ mutex->unlock();
+
+ // Wait to be awakened by a cond_signal() or cond_broadcast().
+ status = semTake(sema_,WAIT_FOREVER);
+
+ // reenable task rescheduling
+ taskUnlock();
+
+ DBG_ASSERT(assert(status == OK));
+
+ if(status != OK)
+ {
+ DBG_TRACE(cout<<"Exception: omni_condition::wait"<<endl);
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+
+ // Reacquire lock to avoid race conditions on the <waiters_> count.
+ status = semTake(waiters_lock_,WAIT_FOREVER);
+
+ DBG_ASSERT(assert(status == OK));
+
+ if(status != OK)
+ {
+ DBG_TRACE(cout<<"Exception: omni_condition::wait"<<endl);
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+
+ // We're ready to return, so there's one less waiter.
+ --waiters_;
+
+ // Release the lock so that other collaborating threads can make
+ // progress.
+ status = semGive(waiters_lock_);
+
+ DBG_ASSERT(assert(status == OK));
+
+ if(status != OK)
+ {
+ DBG_TRACE(cout<<"Exception: omni_condition::wait"<<endl);
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+
+ // Bad things happened, so let's just return below.
+
+ // We must always regain the <external_mutex>, even when errors
+ // occur because that's the guarantee that we give to our callers.
+ mutex->lock();
+}
+
+
+// The time given is absolute. Return 0 is timeout
+int omni_condition::timedwait(unsigned long secs, unsigned long nanosecs)
+{
+ STATUS result = OK;
+ timespec now;
+ unsigned long timeout;
+ int ticks;
+
+ // Prevent race conditions on the <waiters_> count.
+ STATUS status = semTake(waiters_lock_, WAIT_FOREVER);
+
+ DBG_ASSERT(assert(status == OK));
+
+ if(status != OK)
+ {
+ DBG_TRACE(cout<<"Exception: omni_condition::timedwait"<<endl);
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+
+ ++waiters_;
+
+ status = semGive(waiters_lock_);
+
+ DBG_ASSERT(assert(status == OK));
+
+ if(status != OK)
+ {
+ DBG_TRACE(cout<<"Exception: omni_condition::timedwait"<<endl);
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+
+ clock_gettime(CLOCK_REALTIME, &now);
+
+ if(((unsigned long)secs <= (unsigned long)now.tv_sec) &&
+ (((unsigned long)secs < (unsigned long)now.tv_sec) ||
+ (nanosecs < (unsigned long)now.tv_nsec)))
+ timeout = 0;
+ else
+ timeout = (secs-now.tv_sec) * 1000 + (nanosecs-now.tv_nsec) / 1000000l;
+
+ // disable task lock to have an atomic unlock+semTake
+ taskLock();
+
+ // We keep the lock held just long enough to increment the count
+ // of waiters by one.
+ mutex->unlock();
+
+ // Wait to be awakened by a signal() or broadcast().
+ ticks = (timeout * sysClkRateGet()) / 1000L;
+ result = semTake(sema_, ticks);
+
+ // reenable task rescheduling
+ taskUnlock();
+
+ // Reacquire lock to avoid race conditions.
+ status = semTake(waiters_lock_, WAIT_FOREVER);
+
+ DBG_ASSERT(assert(status == OK));
+
+ if(status != OK)
+ {
+ DBG_TRACE(cout<<"Exception: omni_condition::timedwait"<<endl);
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+
+ --waiters_;
+
+ status = semGive(waiters_lock_);
+
+ DBG_ASSERT(assert(status == OK));
+
+ if(status != OK)
+ {
+ DBG_TRACE(cout<<"Exception: omni_condition::timedwait"<<endl);
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+
+ // A timeout has occured - fires exception if the origin is other than timeout
+ if(result!=OK && !(errno == S_objLib_OBJ_TIMEOUT || errno == S_objLib_OBJ_UNAVAILABLE))
+ {
+ DBG_TRACE(cout<<"omni_condition::timedwait! - thread:"<<omni_thread::self()->id()<<" SemID:"<<(int)sema_<<" errno:"<<errno<<endl);
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+
+ // We must always regain the <external_mutex>, even when errors
+ // occur because that's the guarantee that we give to our callers.
+ mutex->lock();
+
+ if(result!=OK) // timeout
+ return 0;
+
+ return 1;
+}
+
+void omni_condition::signal(void)
+{
+ DBG_TRACE(cout<<"omni_condition::signal mutexID: "<<(int)mutex->mutexID<<" tid:"<<(int)taskIdSelf()<<endl);
+
+ STATUS status = semTake(waiters_lock_, WAIT_FOREVER);
+
+ DBG_ASSERT(assert(status == OK));
+
+ if(status != OK)
+ {
+ DBG_TRACE(cout<<"Exception: omni_condition::signal"<<endl);
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+
+ int have_waiters = waiters_ > 0;
+
+ status = semGive(waiters_lock_);
+
+ DBG_ASSERT(assert(status == OK));
+
+ if(status != OK)
+ {
+ DBG_TRACE(cout<<"Exception: omni_condition::signal"<<endl);
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+
+ if(have_waiters != 0)
+ {
+ status = semGive(sema_);
+
+ DBG_ASSERT(assert(status == OK));
+
+ if(status != OK)
+ {
+ DBG_TRACE(cout<<"Exception: omni_condition::signal"<<endl);
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+ }
+}
+
+void omni_condition::broadcast(void)
+{
+ DBG_TRACE(cout<<"omni_condition::broadcast mutexID: "<<(int)mutex->mutexID<<" tid:"<<(int)taskIdSelf()<<endl);
+
+ int have_waiters = 0;
+
+ // The <external_mutex> must be locked before this call is made.
+ // This is needed to ensure that <waiters_> and <was_broadcast_> are
+ // consistent relative to each other.
+ STATUS status = semTake(waiters_lock_, WAIT_FOREVER);
+
+ DBG_ASSERT(assert(status == OK));
+
+ if(status != OK)
+ {
+ DBG_TRACE(cout<<"Exception: omni_condition::signal"<<endl);
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+
+ if(waiters_ > 0)
+ {
+ // We are broadcasting, even if there is just one waiter...
+ // Record the fact that we are broadcasting. This helps the
+ // cond_wait() method know how to optimize itself. Be sure to
+ // set this with the <waiters_lock_> held.
+ have_waiters = 1;
+ }
+
+ status = semGive(waiters_lock_);
+
+ DBG_ASSERT(assert(status == OK));
+
+ if(status != OK)
+ {
+ DBG_TRACE(cout<<"Exception: omni_condition::signal"<<endl);
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+
+ if(have_waiters)
+ {
+ // Wake up all the waiters.
+ status = semFlush(sema_);
+
+ DBG_ASSERT(assert(status == OK));
+
+ if(status != OK)
+ {
+ DBG_TRACE(cout<<"omni_condition::broadcast1! - thread:"<<omni_thread::self()->id()<<" SemID:"<<(int)sema_<<" errno:"<<errno<<endl);
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Counting semaphore
+//
+///////////////////////////////////////////////////////////////////////////
+omni_semaphore::omni_semaphore(unsigned int initial)
+{
+
+ DBG_ASSERT(assert(0 <= (int)initial)); // POSIX expects only unsigned init values
+
+ semID = semCCreate(SEM_Q_PRIORITY, (int)initial);
+
+ DBG_ASSERT(assert(semID!=NULL));
+
+ if(semID==NULL)
+ {
+ DBG_TRACE(cout<<"Exception: omni_semaphore::omni_semaphore"<<endl);
+ DBG_THROW(throw omni_thread_fatal(-1));
+ }
+}
+
+omni_semaphore::~omni_semaphore(void)
+{
+ STATUS status = semDelete(semID);
+
+ DBG_ASSERT(assert(status == OK));
+
+ if(status != OK)
+ {
+ DBG_TRACE(cout<<"Exception: omni_semaphore::~omni_semaphore"<<endl);
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+}
+
+void omni_semaphore::wait(void)
+{
+ DBG_ASSERT(assert(!intContext())); // no wait in ISR
+
+ STATUS status = semTake(semID, WAIT_FOREVER);
+
+ DBG_ASSERT(assert(status == OK));
+
+ if(status != OK)
+ {
+ DBG_TRACE(cout<<"Exception: omni_semaphore::wait"<<endl);
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+}
+
+int omni_semaphore::trywait(void)
+{
+ STATUS status = semTake(semID, NO_WAIT);
+
+ DBG_ASSERT(assert(status == OK));
+
+ if(status != OK)
+ {
+ if(errno == S_objLib_OBJ_UNAVAILABLE)
+ {
+ return 0;
+ }
+ else
+ {
+ DBG_ASSERT(assert(false));
+
+ DBG_TRACE(cout<<"Exception: omni_semaphore::trywait"<<endl);
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+ }
+
+ return 1;
+}
+
+void omni_semaphore::post(void)
+{
+ STATUS status = semGive(semID);
+
+ DBG_ASSERT(assert(status == OK));
+
+ if(status != OK)
+ {
+ DBG_TRACE(cout<<"Exception: omni_semaphore::post"<<endl);
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Thread
+//
+///////////////////////////////////////////////////////////////////////////
+
+
+//
+// static variables
+//
+omni_mutex* omni_thread::next_id_mutex = 0;
+int omni_thread::next_id = 0;
+
+// omniORB requires a larger stack size than the default (21120) on OSF/1
+static size_t stack_size = OMNI_STACK_SIZE;
+
+
+//
+// Initialisation function (gets called before any user code).
+//
+
+static int& count() {
+ static int the_count = 0;
+ return the_count;
+}
+
+omni_thread::init_t::init_t(void)
+{
+ // Only do it once however many objects get created.
+ if(count()++ != 0)
+ return;
+
+ attach();
+}
+
+omni_thread::init_t::~init_t(void)
+{
+ if (--count() != 0) return;
+
+ omni_thread* self = omni_thread::self();
+ if (!self) return;
+
+ taskTcb(taskIdSelf())->spare1 = 0;
+ delete self;
+
+ delete next_id_mutex;
+}
+
+
+//
+// Wrapper for thread creation.
+//
+extern "C" void omni_thread_wrapper(void* ptr)
+{
+ omni_thread* me = (omni_thread*)ptr;
+
+ DBG_TRACE(cout<<"omni_thread_wrapper: thread "<<me->id()<<" started\n");
+
+ //
+ // We can now tweaked the task info since the tcb exist now
+ //
+ me->mutex.lock(); // To ensure that start has had time to finish
+ taskTcb(me->tid)->spare1 = OMNI_THREAD_ID;
+ taskTcb(me->tid)->spare2 = (int)ptr;
+ me->mutex.unlock();
+
+ //
+ // Now invoke the thread function with the given argument.
+ //
+ if(me->fn_void != NULL)
+ {
+ (*me->fn_void)(me->thread_arg);
+ omni_thread::exit();
+ }
+
+ if(me->fn_ret != NULL)
+ {
+ void* return_value = (*me->fn_ret)(me->thread_arg);
+ omni_thread::exit(return_value);
+ }
+
+ if(me->detached)
+ {
+ me->run(me->thread_arg);
+ omni_thread::exit();
+ }
+ else
+ {
+ void* return_value = me->run_undetached(me->thread_arg);
+ omni_thread::exit(return_value);
+ }
+}
+
+
+//
+// Special functions for VxWorks only
+//
+void omni_thread::attach(void)
+{
+ DBG_TRACE(cout<<"omni_thread_attach: VxWorks mapping thread initialising\n");
+
+ int _tid = taskIdSelf();
+
+ // Check the task is not already attached
+ if(taskTcb(_tid)->spare1 == OMNI_THREAD_ID)
+ return;
+
+ // Create the mutex required to lock the threads debugging id (create before the thread!!!)
+ if(next_id_mutex == 0)
+ next_id_mutex = new omni_mutex;
+
+ // Create a thread object for THIS running process
+ omni_thread* t = new omni_thread;
+
+ // Lock its mutex straigh away!
+ omni_mutex_lock l(t->mutex);
+
+ // Adjust data members of this instance
+ t->_state = STATE_RUNNING;
+ t->tid = taskIdSelf();
+
+ // Set the thread values so it can be recongnised as a omni_thread
+ // Set the id last can possibly prevent race condition
+ taskTcb(t->tid)->spare2 = (int)t;
+ taskTcb(t->tid)->spare1 = OMNI_THREAD_ID;
+
+ // Create the running_mutex at this stage, but leave it empty. We are not running
+ // in the task context HERE, so taking it would be disastrous.
+ t->running_cond = new omni_condition(&t->mutex);
+}
+
+
+void omni_thread::detach(void)
+{
+ DBG_TRACE(cout<<"omni_thread_detach: VxWorks detaching thread mapping\n");
+
+ int _tid = taskIdSelf();
+
+ // Check the task has a OMNI_THREAD attached
+ if(taskTcb(_tid)->spare1 != OMNI_THREAD_ID)
+ return;
+
+ // Invalidate the id NOW !
+ taskTcb(_tid)->spare1 = 0;
+
+ // Even if NULL, it is safe to delete the thread
+ omni_thread* t = (omni_thread*)taskTcb(_tid)->spare2;
+ // Fininsh cleaning the tcb structure
+ taskTcb(_tid)->spare2 = 0;
+
+ delete t;
+}
+
+
+//
+// Constructors for omni_thread - set up the thread object but don't
+// start it running.
+//
+
+// construct a detached thread running a given function.
+omni_thread::omni_thread(void (*fn)(void*), void* arg, priority_t pri)
+{
+ common_constructor(arg, pri, 1);
+ fn_void = fn;
+ fn_ret = NULL;
+}
+
+// construct an undetached thread running a given function.
+omni_thread::omni_thread(void* (*fn)(void*), void* arg, priority_t pri)
+{
+ common_constructor(arg, pri, 0);
+ fn_void = NULL;
+ fn_ret = fn;
+}
+
+// construct a thread which will run either run() or run_undetached().
+
+omni_thread::omni_thread(void* arg, priority_t pri)
+{
+ common_constructor(arg, pri, 1);
+ fn_void = NULL;
+ fn_ret = NULL;
+}
+
+// common part of all constructors.
+void omni_thread::common_constructor(void* arg, priority_t pri, int det)
+{
+ _state = STATE_NEW;
+ _priority = pri;
+
+ // Set the debugging id
+ next_id_mutex->lock();
+ _id = next_id++;
+ next_id_mutex->unlock();
+
+ // Note : tid can only be setup when the task is up and running
+ tid = 0;
+
+ thread_arg = arg;
+ detached = det; // may be altered in start_undetached()
+
+ _dummy = 0;
+ _values = 0;
+ _value_alloc = 0;
+}
+
+//
+// Destructor for omni_thread.
+//
+omni_thread::~omni_thread(void)
+{
+ DBG_TRACE(cout<<"omni_thread::~omni_thread for thread "<<id()<<endl);
+
+ if (_values) {
+ for (key_t i=0; i < _value_alloc; i++) {
+ if (_values[i]) {
+ delete _values[i];
+ }
+ }
+ delete [] _values;
+ }
+
+ delete running_cond;
+}
+
+
+//
+// Start the thread
+//
+void omni_thread::start(void)
+{
+ omni_mutex_lock l(mutex);
+
+ DBG_ASSERT(assert(_state == STATE_NEW));
+
+ if(_state != STATE_NEW)
+ DBG_THROW(throw omni_thread_invalid());
+
+ // Allocate memory for the task. (The returned id cannot be trusted by the task)
+ tid = taskSpawn(
+ NULL, // Task name
+ vxworks_priority(_priority), // Priority
+ 0, // Option
+ stack_size, // Stack size
+ (FUNCPTR)omni_thread_wrapper, // Priority
+ (int)this, // First argument is this
+ 0,0,0,0,0,0,0,0,0 // Remaining unused args
+ );
+
+ DBG_ASSERT(assert(tid!=ERROR));
+
+ if(tid==ERROR)
+ DBG_THROW(throw omni_thread_invalid());
+
+ _state = STATE_RUNNING;
+
+ // Create the running_mutex at this stage, but leave it empty. We are not running
+ // in the task context HERE, so taking it would be disastrous.
+ running_cond = new omni_condition(&mutex);
+}
+
+
+//
+// Start a thread which will run the member function run_undetached().
+//
+void omni_thread::start_undetached(void)
+{
+ DBG_ASSERT(assert(!((fn_void != NULL) || (fn_ret != NULL))));
+
+ if((fn_void != NULL) || (fn_ret != NULL))
+ DBG_THROW(throw omni_thread_invalid());
+
+ detached = 0;
+
+ start();
+}
+
+
+//
+// join - Wait for the task to complete before returning to the calling process
+//
+void omni_thread::join(void** status)
+{
+ mutex.lock();
+
+ if((_state != STATE_RUNNING) && (_state != STATE_TERMINATED))
+ {
+ mutex.unlock();
+
+ DBG_ASSERT(assert(false));
+
+ DBG_THROW(throw omni_thread_invalid());
+ }
+
+ mutex.unlock();
+
+ DBG_ASSERT(assert(this != self()));
+
+ if(this == self())
+ DBG_THROW(throw omni_thread_invalid());
+
+ DBG_ASSERT(assert(!detached));
+
+ if(detached)
+ DBG_THROW(throw omni_thread_invalid());
+
+ mutex.lock();
+ running_cond->wait();
+ mutex.unlock();
+
+ if(status)
+ *status = return_val;
+
+ delete this;
+}
+
+
+//
+// Change this thread's priority.
+//
+void omni_thread::set_priority(priority_t pri)
+{
+ omni_mutex_lock l(mutex);
+
+ DBG_ASSERT(assert(_state == STATE_RUNNING));
+
+ if(_state != STATE_RUNNING)
+ {
+ DBG_THROW(throw omni_thread_invalid());
+ }
+
+ _priority = pri;
+
+ if(taskPrioritySet(tid, vxworks_priority(pri))==ERROR)
+ {
+ DBG_ASSERT(assert(false));
+
+ DBG_THROW(throw omni_thread_fatal(errno));
+ }
+}
+
+
+//
+// create - construct a new thread object and start it running. Returns thread
+// object if successful, null pointer if not.
+//
+
+// detached version (the entry point is a void)
+omni_thread* omni_thread::create(void (*fn)(void*), void* arg, priority_t pri)
+{
+ omni_thread* t = new omni_thread(fn, arg, pri);
+
+ t->start();
+
+ return t;
+}
+
+// undetached version (the entry point is a void*)
+omni_thread* omni_thread::create(void* (*fn)(void*), void* arg, priority_t pri)
+{
+ omni_thread* t = new omni_thread(fn, arg, pri);
+
+ t->start();
+
+ return t;
+}
+
+
+//
+// exit() _must_ lock the mutex even in the case of a detached thread. This is
+// because a thread may run to completion before the thread that created it has
+// had a chance to get out of start(). By locking the mutex we ensure that the
+// creating thread must have reached the end of start() before we delete the
+// thread object. Of course, once the call to start() returns, the user can
+// still incorrectly refer to the thread object, but that's their problem.
+//
+void omni_thread::exit(void* return_value)
+{
+ omni_thread* me = self();
+
+ if(me)
+ {
+ me->mutex.lock();
+
+ me->return_val = return_value;
+ me->_state = STATE_TERMINATED;
+ me->running_cond->signal();
+
+ me->mutex.unlock();
+
+ DBG_TRACE(cout<<"omni_thread::exit: thread "<<me->id()<<" detached "<<me->detached<<" return value "<<(int)return_value<<endl);
+
+ if(me->detached)
+ delete me;
+ }
+ else
+ DBG_TRACE(cout<<"omni_thread::exit: called with a non-omnithread. Exit quietly."<<endl);
+
+ taskDelete(taskIdSelf());
+}
+
+
+omni_thread* omni_thread::self(void)
+{
+ if(taskTcb(taskIdSelf())->spare1 != OMNI_THREAD_ID)
+ return NULL;
+
+ return (omni_thread*)taskTcb(taskIdSelf())->spare2;
+}
+
+
+void omni_thread::yield(void)
+{
+ taskDelay(NO_WAIT);
+}
+
+
+void omni_thread::sleep(unsigned long secs, unsigned long nanosecs)
+{
+ int tps = sysClkRateGet();
+
+ // Convert to us to avoid overflow in the multiplication
+ // tps should always be less than 1000 !
+ nanosecs /= 1000;
+
+ taskDelay(secs*tps + (nanosecs*tps)/1000000l);
+}
+
+
+void omni_thread::get_time( unsigned long* abs_sec,
+ unsigned long* abs_nsec,
+ unsigned long rel_sec,
+ unsigned long rel_nsec)
+{
+ timespec abs;
+ clock_gettime(CLOCK_REALTIME, &abs);
+ abs.tv_nsec += rel_nsec;
+ abs.tv_sec += rel_sec + abs.tv_nsec / 1000000000;
+ abs.tv_nsec = abs.tv_nsec % 1000000000;
+ *abs_sec = abs.tv_sec;
+ *abs_nsec = abs.tv_nsec;
+}
+
+
+int omni_thread::vxworks_priority(priority_t pri)
+{
+ switch (pri)
+ {
+ case PRIORITY_LOW:
+ return omni_thread_prio_low;
+
+ case PRIORITY_NORMAL:
+ return omni_thread_prio_normal;
+
+ case PRIORITY_HIGH:
+ return omni_thread_prio_high;
+ }
+
+ DBG_ASSERT(assert(false));
+
+ DBG_THROW(throw omni_thread_invalid());
+}
+
+
+void omni_thread::stacksize(unsigned long sz)
+{
+ stack_size = sz;
+}
+
+
+unsigned long omni_thread::stacksize()
+{
+ return stack_size;
+}
+
+
+void omni_thread::show(void)
+{
+ omni_thread *pThread;
+ int s1, s2;
+ int tid = taskIdSelf();
+
+ printf("TaskId is %.8x\n", tid);
+
+ s1 = taskTcb(tid)->spare1;
+
+ if(s1 != OMNI_THREAD_ID)
+ {
+ printf("Spare 1 is %.8x, and not recongnized\n", s1);
+
+ return;
+ }
+ else
+ {
+ printf("Spare 1 indicate an omni_thread.\n");
+ }
+
+ s2 = taskTcb(tid)->spare2;
+
+ if(s2 == 0)
+ {
+ printf("Spare 2 is NULL! - No thread object attached !!\n");
+
+ return;
+ }
+ else
+ {
+ printf("Thread object at %.8x\n", s2);
+ }
+
+ pThread = (omni_thread *)s2;
+
+ state_t status = pThread->_state;
+
+ printf(" | Thread status is ");
+
+ switch (status)
+ {
+ case STATE_NEW:
+ printf("NEW\n"); break;
+ case STATE_RUNNING:
+ printf("STATE_RUNNING\n"); break;
+ case STATE_TERMINATED:
+ printf("TERMINATED\n"); break;
+ default:
+ printf("Illegal (=%.8x)\n", (unsigned int)status);
+
+ return;
+ }
+
+ if(pThread->tid != tid)
+ {
+ printf(" | Task ID in thread object is different!! (=%.8x)\n", pThread->tid);
+
+ return;
+ }
+ else
+ {
+ printf(" | Task ID in thread consistent\n");
+ }
+
+ printf("\n");
+}
+
+
+//
+// Dummy thread
+//
+
+class omni_thread_dummy : public omni_thread {
+public:
+ inline omni_thread_dummy() : omni_thread()
+ {
+ _dummy = 1;
+ _state = STATE_RUNNING;
+
+ // Adjust data members of this instance
+ tid = taskIdSelf();
+
+ // Set the thread values so it can be recongnised as a omni_thread
+ // Set the id last can possibly prevent race condition
+ taskTcb(tid)->spare2 = (int)this;
+ taskTcb(tid)->spare1 = OMNI_THREAD_ID;
+ }
+ inline ~omni_thread_dummy()
+ {
+ taskTcb(taskIdSelf())->spare1 = 0;
+ }
+};
+
+omni_thread*
+omni_thread::create_dummy()
+{
+ if (omni_thread::self())
+ throw omni_thread_invalid();
+
+ return new omni_thread_dummy;
+}
+
+void
+omni_thread::release_dummy()
+{
+ omni_thread* self = omni_thread::self();
+ if (!self || !self->_dummy)
+ throw omni_thread_invalid();
+
+ omni_thread_dummy* dummy = (omni_thread_dummy*)self;
+ delete dummy;
+}
+
+
+#define INSIDE_THREAD_IMPL_CC
+#include "threaddata.cc"
+#undef INSIDE_THREAD_IMPL_CC