From: eb Date: Tue, 30 Jan 2007 02:12:05 +0000 (+0000) Subject: Merged eb/omni -r4315:4327 into trunk. X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=6ff1faed9d4c7095ab2d07b99478fe46e35f0e1e;p=debian%2Fgnuradio 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 --- diff --git a/Makefile.common b/Makefile.common index e7d92868..56d7f5ca 100644 --- a/Makefile.common +++ b/Makefile.common @@ -50,7 +50,6 @@ GNURADIO_INCLUDES = -I$(top_srcdir)/gnuradio-core/src/lib/runtime \ -I$(top_srcdir)/gnuradio-core/src/lib/reed-solomon \ -I$(top_srcdir)/gnuradio-core/src/lib/io \ -I$(top_srcdir)/gnuradio-core/src/lib/g72x \ - -I$(top_srcdir)/gnuradio-core/src/lib/omnithread \ -I$(top_srcdir)/gnuradio-core/src/lib/swig \ -I$(top_builddir)/gnuradio-core/src/lib/swig \ $(FFTW3F_CFLAGS) @@ -58,6 +57,7 @@ GNURADIO_INCLUDES = -I$(top_srcdir)/gnuradio-core/src/lib/runtime \ # These used to be set in PKGCONFIG but now point to the current # build tree. +# FIXME shouldn't -lfftw3f -lm just be extracted from libgnuradio-core.la ??? GNURADIO_CORE_LIBS = -L$(top_builddir)/gnuradio-core/src/lib \ -lgnuradio-core -lfftw3f -lm @@ -69,15 +69,17 @@ GNURADIO_I = $(top_srcdir)/gnuradio-core/src/lib/swig/gnuradio.i USRP_INCLUDES = -I$(top_srcdir)/usrp/host/lib \ -I$(top_srcdir)/usrp/firmware/include -USRP_LIBS = -L$(top_builddir)/usrp/host/lib \ - -lusrp +USRP_LIBS = -L$(top_builddir)/usrp/host/lib -lusrp PMT_INCLUDES = -I$(top_srcdir)/pmt/src/lib PMT_LIBS = -L$(top_builddir)/pmt/src/lib -lpmt +OMNITHREAD_INCLUDES = -I$(top_srcdir)/omnithread +OMNITHREAD_LIBS = -L$(top_builddir)/omnithread -lgromnithread + # This used to be set in configure.ac but is now defined here for all # Makefiles when this fragment is included. -STD_DEFINES_AND_INCLUDES=$(DEFINES) $(GNURADIO_INCLUDES) $(BOOST_CFLAGS) +STD_DEFINES_AND_INCLUDES=$(DEFINES) $(OMNITHREAD_INCLUDES) $(GNURADIO_INCLUDES) $(BOOST_CFLAGS) # Fix for BSD make not defining $(RM). We define it now in configure.ac # using AM_PATH_PROG, but now here have to add a -f to be like GNU make diff --git a/config/grc_gnuradio_core.m4 b/config/grc_gnuradio_core.m4 index da91f61e..6b9c8542 100644 --- a/config/grc_gnuradio_core.m4 +++ b/config/grc_gnuradio_core.m4 @@ -1,4 +1,4 @@ -dnl Copyright 2001,2002,2003,2004,2005,2006 Free Software Foundation, Inc. +dnl Copyright 2001,2002,2003,2004,2005,2006,2007 Free Software Foundation, Inc. dnl dnl This file is part of GNU Radio dnl @@ -37,7 +37,6 @@ AC_DEFUN([GRC_GNURADIO_CORE],[ gnuradio-core/src/lib/gengen/Makefile \ gnuradio-core/src/lib/io/Makefile \ gnuradio-core/src/lib/missing/Makefile \ - gnuradio-core/src/lib/omnithread/Makefile \ gnuradio-core/src/lib/reed-solomon/Makefile \ gnuradio-core/src/lib/runtime/Makefile \ gnuradio-core/src/lib/swig/Makefile \ @@ -55,6 +54,16 @@ AC_DEFUN([GRC_GNURADIO_CORE],[ ]) passed=yes + # Don't do gnuradio-core if omnithread skipped + # There *has* to be a better way to check if a value is in a string + for dir in $skipped_dirs + do + if test x$dir = xomnithread; then + AC_MSG_RESULT([Component gnuradio-core requires omnithread, which is not being built.]) + passed=no + fi + done + GRC_BUILD_CONDITIONAL([gnuradio-core],[ dnl run_tests is created from run_tests.in. Make it executable. AC_CONFIG_COMMANDS([run_tests_core], [chmod +x gnuradio-core/src/python/gnuradio/gr/run_tests]) diff --git a/config/grc_mblock.m4 b/config/grc_mblock.m4 index a8fba4e0..6e4bc4af 100644 --- a/config/grc_mblock.m4 +++ b/config/grc_mblock.m4 @@ -28,6 +28,16 @@ AC_DEFUN([GRC_MBLOCK],[ ]) passed=yes + # Don't do mblock if omnithread skipped + # There *has* to be a better way to check if a value is in a string + for dir in $skipped_dirs + do + if test x$dir = xomnithread; then + AC_MSG_RESULT([Component mblock requires omnithread, which is not being built.]) + passed=no + fi + done + # Don't do mblock if pmt skipped # There *has* to be a better way to check if a value is in a string for dir in $skipped_dirs diff --git a/config/grc_omnithread.m4 b/config/grc_omnithread.m4 new file mode 100644 index 00000000..627ccdc9 --- /dev/null +++ b/config/grc_omnithread.m4 @@ -0,0 +1,33 @@ +dnl Copyright 2001,2002,2003,2004,2005,2006,2007 Free Software Foundation, Inc. +dnl +dnl This file is part of GNU Radio +dnl +dnl GNU Radio is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl GNU Radio is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with GNU Radio; see the file COPYING. If not, write to +dnl the Free Software Foundation, Inc., 51 Franklin Street, +dnl Boston, MA 02110-1301, USA. + +AC_DEFUN([GRC_OMNITHREAD],[ + GRC_ENABLE([omnithread]) + + AC_CONFIG_FILES([ \ + omnithread/Makefile \ + ]) + + passed=yes + GRC_BUILD_CONDITIONAL([omnithread],[ + dnl run_tests is created from run_tests.in. Make it executable. + dnl AC_CONFIG_COMMANDS([run_tests_omnithread], [chmod +x omnithread/run_tests]) + + ]) +]) diff --git a/configure.ac b/configure.ac index 924ad88a..7fc963c3 100644 --- a/configure.ac +++ b/configure.ac @@ -184,6 +184,7 @@ AC_ARG_ENABLE( ) build_dirs="config" +GRC_OMNITHREAD dnl must come before gnuradio-core and mblock GRC_GNURADIO_CORE GRC_USRP GRC_GR_USRP dnl this must come after GRC_USRP diff --git a/gnuradio-core/gnuradio-core.pc.in b/gnuradio-core/gnuradio-core.pc.in index cc6c03ac..9a8f6736 100644 --- a/gnuradio-core/gnuradio-core.pc.in +++ b/gnuradio-core/gnuradio-core.pc.in @@ -7,5 +7,5 @@ Name: gnuradio-core Description: GNU Software Radio toolkit Requires: Version: @VERSION@ -Libs: -L${libdir} -lgnuradio-core @FFTW3F_LIBS@ +Libs: -L${libdir} -lgnuradio-core @FFTW3F_LIBS@ @OMNITHREAD_LIBS@ Cflags: -I${includedir} @DEFINES@ @PTHREAD_CFLAGS@ diff --git a/gnuradio-core/src/lib/Makefile.am b/gnuradio-core/src/lib/Makefile.am index 96a89170..70a4de08 100644 --- a/gnuradio-core/src/lib/Makefile.am +++ b/gnuradio-core/src/lib/Makefile.am @@ -24,7 +24,7 @@ include $(top_srcdir)/Makefile.common ## Process this file with automake to produce Makefile.in # We've got to build . before swig -SUBDIRS = missing runtime filter general gengen g72x reed-solomon omnithread io . swig +SUBDIRS = missing runtime filter general gengen g72x reed-solomon io . swig # generate libgnuradio-core.la from the convenience libraries in subdirs @@ -35,7 +35,7 @@ libgnuradio_core_la_LDFLAGS = $(NO_UNDEFINED) -version-info 0:0:0 libgnuradio_core_qa_la_SOURCES = bug_work_around_6.cc libgnuradio_core_qa_la_LDFLAGS = $(NO_UNDEFINED) -version-info 0:0:0 \ - $(LIBGNURADIO_CORE_EXTRA_LDFLAGS) + $(LIBGNURADIO_CORE_EXTRA_LDFLAGS) libgnuradio_core_la_LIBADD = \ filter/libfilter.la \ @@ -44,9 +44,9 @@ libgnuradio_core_la_LIBADD = \ gengen/libgengen.la \ io/libio.la \ missing/libmissing.la \ - omnithread/libomnithread.la \ reed-solomon/librs.la \ runtime/libruntime.la \ + $(OMNITHREAD_LIBS) \ $(FFTW3F_LIBS) libgnuradio_core_qa_la_LIBADD = \ diff --git a/gnuradio-core/src/lib/omnithread/Makefile.am b/gnuradio-core/src/lib/omnithread/Makefile.am deleted file mode 100644 index de365c15..00000000 --- a/gnuradio-core/src/lib/omnithread/Makefile.am +++ /dev/null @@ -1,67 +0,0 @@ -# -# 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 = $(STD_DEFINES_AND_INCLUDES) $(OMNITHREAD_DEFINES) - -noinst_LTLIBRARIES = libomnithread.la - -# At this point we only support the posix and nt pthreads i/f... - -if OMNITHREAD_POSIX -libomnithread_la_SOURCES = \ - posix.cc -endif - -if OMNITHREAD_NT -libomnithread_la_SOURCES = \ - nt.cc -endif - -libomnithread_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/gnuradio-core/src/lib/omnithread/dir.mk b/gnuradio-core/src/lib/omnithread/dir.mk deleted file mode 100644 index d5380341..00000000 --- a/gnuradio-core/src/lib/omnithread/dir.mk +++ /dev/null @@ -1,229 +0,0 @@ -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/gnuradio-core/src/lib/omnithread/mach.cc b/gnuradio-core/src/lib/omnithread/mach.cc deleted file mode 100644 index 8759bb4c..00000000 --- a/gnuradio-core/src/lib/omnithread/mach.cc +++ /dev/null @@ -1,714 +0,0 @@ -// 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 -#include -#include -#include -#include "omnithread.h" - -#define DB(x) // x -// #include or #include 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/gnuradio-core/src/lib/omnithread/nt.cc b/gnuradio-core/src/lib/omnithread/nt.cc deleted file mode 100644 index 3853f010..00000000 --- a/gnuradio-core/src/lib/omnithread/nt.cc +++ /dev/null @@ -1,969 +0,0 @@ -// 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 -#endif - -#include -#include -#include -#include -#include - -#define DB(x) // x -//#include or #include 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/gnuradio-core/src/lib/omnithread/omnithread.h b/gnuradio-core/src/lib/omnithread/omnithread.h deleted file mode 100644 index b6df34d7..00000000 --- a/gnuradio-core/src/lib/omnithread/omnithread.h +++ /dev/null @@ -1,622 +0,0 @@ -// -*- 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 -#endif - -#if defined(OMNITHREAD_POSIX) -#include - -#elif defined(OMNITHREAD_NT) -#include - -#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 - -#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 -#else -#include -#endif - -#elif defined(__rtems__) -#include -#include - -#elif defined(__macos__) -#include -#include - -#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/gnuradio-core/src/lib/omnithread/ot_VxThread.h b/gnuradio-core/src/lib/omnithread/ot_VxThread.h deleted file mode 100644 index e96c036c..00000000 --- a/gnuradio-core/src/lib/omnithread/ot_VxThread.h +++ /dev/null @@ -1,118 +0,0 @@ -#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 -#include -#include - - -/////////////////////////////////////////////////////////////////////////// -// 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/gnuradio-core/src/lib/omnithread/ot_mach.h b/gnuradio-core/src/lib/omnithread/ot_mach.h deleted file mode 100644 index 76361926..00000000 --- a/gnuradio-core/src/lib/omnithread/ot_mach.h +++ /dev/null @@ -1,51 +0,0 @@ -// 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 - -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/gnuradio-core/src/lib/omnithread/ot_nt.h b/gnuradio-core/src/lib/omnithread/ot_nt.h deleted file mode 100644 index 551ccf2f..00000000 --- a/gnuradio-core/src/lib/omnithread/ot_nt.h +++ /dev/null @@ -1,85 +0,0 @@ -// 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 - -#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/gnuradio-core/src/lib/omnithread/ot_posix.h b/gnuradio-core/src/lib/omnithread/ot_posix.h deleted file mode 100644 index 666ccc08..00000000 --- a/gnuradio-core/src/lib/omnithread/ot_posix.h +++ /dev/null @@ -1,81 +0,0 @@ -// 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 -#else -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# define OMNI_DEFINED_WIN32_LEAN_AND_MEAN -# endif -# include -# 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/gnuradio-core/src/lib/omnithread/ot_pthread_nt.h b/gnuradio-core/src/lib/omnithread/ot_pthread_nt.h deleted file mode 100644 index dbf4356c..00000000 --- a/gnuradio-core/src/lib/omnithread/ot_pthread_nt.h +++ /dev/null @@ -1,186 +0,0 @@ -/* Package : omnithread - omnithread/pthread_nt.h Created : Steven Brenneis - - 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 - -#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/gnuradio-core/src/lib/omnithread/ot_solaris.h b/gnuradio-core/src/lib/omnithread/ot_solaris.h deleted file mode 100644 index f4fea0b1..00000000 --- a/gnuradio-core/src/lib/omnithread/ot_solaris.h +++ /dev/null @@ -1,47 +0,0 @@ -// 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 - -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/gnuradio-core/src/lib/omnithread/posix.cc b/gnuradio-core/src/lib/omnithread/posix.cc deleted file mode 100644 index b82e86df..00000000 --- a/gnuradio-core/src/lib/omnithread/posix.cc +++ /dev/null @@ -1,972 +0,0 @@ -// 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 -#include -#include -#include -#include - -#ifdef HAVE_NANOSLEEP -#undef NoNanoSleep -#else -#define NoNanoSleep -#endif - -#ifdef HAVE_SYS_TIME_H -// typedef of struct timeval and gettimeofday(); -#include -#include -#endif - -#if defined(__linux__) && defined(_MIT_POSIX_THREADS) -#include -#endif - -#if defined(__irix__) && defined(PthreadSupportThreadPriority) -#if _POSIX_THREAD_PRIORITY_SCHEDULING -#include -#endif -#endif - -#define DB(x) // x -//#include or #include 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/gnuradio-core/src/lib/omnithread/solaris.cc b/gnuradio-core/src/lib/omnithread/solaris.cc deleted file mode 100644 index b0139d29..00000000 --- a/gnuradio-core/src/lib/omnithread/solaris.cc +++ /dev/null @@ -1,615 +0,0 @@ -// 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 -#include -#include - -#define DB(x) // x -// #include or #include 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/gnuradio-core/src/lib/omnithread/threaddata.cc b/gnuradio-core/src/lib/omnithread/threaddata.cc deleted file mode 100644 index d54c4391..00000000 --- a/gnuradio-core/src/lib/omnithread/threaddata.cc +++ /dev/null @@ -1,83 +0,0 @@ -// 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/gnuradio-core/src/lib/omnithread/vxWorks.cc b/gnuradio-core/src/lib/omnithread/vxWorks.cc deleted file mode 100644 index 25634ce9..00000000 --- a/gnuradio-core/src/lib/omnithread/vxWorks.cc +++ /dev/null @@ -1,1160 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// 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 -#include -#include -#include -#include -#include - -#include // assert -#include // 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 - #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()<mutexID<<" tid:"<<(int)taskIdSelf()<mutexID<<" tid:"<<(int)taskIdSelf()< count. - - STATUS status = semTake(waiters_lock_,WAIT_FOREVER); - - DBG_ASSERT(assert(status == OK)); - - if(status != OK) - { - DBG_TRACE(cout<<"Exception: omni_condition::wait"<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"< count. - status = semTake(waiters_lock_,WAIT_FOREVER); - - DBG_ASSERT(assert(status == OK)); - - if(status != OK) - { - DBG_TRACE(cout<<"Exception: omni_condition::wait"<, 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 count. - STATUS status = semTake(waiters_lock_, WAIT_FOREVER); - - DBG_ASSERT(assert(status == OK)); - - if(status != OK) - { - DBG_TRACE(cout<<"Exception: omni_condition::timedwait"<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"<id()<<" SemID:"<<(int)sema_<<" errno:"<, 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()< 0; - - status = semGive(waiters_lock_); - - DBG_ASSERT(assert(status == OK)); - - if(status != OK) - { - DBG_TRACE(cout<<"Exception: omni_condition::signal"<mutexID<<" tid:"<<(int)taskIdSelf()< must be locked before this call is made. - // This is needed to ensure that and 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"< 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 held. - have_waiters = 1; - } - - status = semGive(waiters_lock_); - - DBG_ASSERT(assert(status == OK)); - - if(status != OK) - { - DBG_TRACE(cout<<"Exception: omni_condition::signal"<id()<<" SemID:"<<(int)sema_<<" errno:"<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 "<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 "<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 "<id()<<" detached "<detached<<" return value "<<(int)return_value<detached) - delete me; - } - else - DBG_TRACE(cout<<"omni_thread::exit: called with a non-omnithread. Exit quietly."<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 diff --git a/omnithread/Makefile.am b/omnithread/Makefile.am new file mode 100644 index 00000000..2eac4c92 --- /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 00000000..d5380341 --- /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 00000000..8759bb4c --- /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 +#include +#include +#include +#include "omnithread.h" + +#define DB(x) // x +// #include or #include 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 00000000..3853f010 --- /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 +#endif + +#include +#include +#include +#include +#include + +#define DB(x) // x +//#include or #include 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 00000000..b6df34d7 --- /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 +#endif + +#if defined(OMNITHREAD_POSIX) +#include + +#elif defined(OMNITHREAD_NT) +#include + +#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 + +#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 +#else +#include +#endif + +#elif defined(__rtems__) +#include +#include + +#elif defined(__macos__) +#include +#include + +#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 00000000..e96c036c --- /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 +#include +#include + + +/////////////////////////////////////////////////////////////////////////// +// 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 00000000..76361926 --- /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 + +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 00000000..551ccf2f --- /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 + +#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 00000000..666ccc08 --- /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 +#else +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# define OMNI_DEFINED_WIN32_LEAN_AND_MEAN +# endif +# include +# 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 00000000..dbf4356c --- /dev/null +++ b/omnithread/ot_pthread_nt.h @@ -0,0 +1,186 @@ +/* Package : omnithread + omnithread/pthread_nt.h Created : Steven Brenneis + + 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 + +#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 00000000..f4fea0b1 --- /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 + +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 00000000..b82e86df --- /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 +#include +#include +#include +#include + +#ifdef HAVE_NANOSLEEP +#undef NoNanoSleep +#else +#define NoNanoSleep +#endif + +#ifdef HAVE_SYS_TIME_H +// typedef of struct timeval and gettimeofday(); +#include +#include +#endif + +#if defined(__linux__) && defined(_MIT_POSIX_THREADS) +#include +#endif + +#if defined(__irix__) && defined(PthreadSupportThreadPriority) +#if _POSIX_THREAD_PRIORITY_SCHEDULING +#include +#endif +#endif + +#define DB(x) // x +//#include or #include 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 00000000..b0139d29 --- /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 +#include +#include + +#define DB(x) // x +// #include or #include 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 00000000..d54c4391 --- /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 00000000..25634ce9 --- /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 +#include +#include +#include +#include +#include + +#include // assert +#include // 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 + #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()<mutexID<<" tid:"<<(int)taskIdSelf()<mutexID<<" tid:"<<(int)taskIdSelf()< count. + + STATUS status = semTake(waiters_lock_,WAIT_FOREVER); + + DBG_ASSERT(assert(status == OK)); + + if(status != OK) + { + DBG_TRACE(cout<<"Exception: omni_condition::wait"<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"< count. + status = semTake(waiters_lock_,WAIT_FOREVER); + + DBG_ASSERT(assert(status == OK)); + + if(status != OK) + { + DBG_TRACE(cout<<"Exception: omni_condition::wait"<, 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 count. + STATUS status = semTake(waiters_lock_, WAIT_FOREVER); + + DBG_ASSERT(assert(status == OK)); + + if(status != OK) + { + DBG_TRACE(cout<<"Exception: omni_condition::timedwait"<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"<id()<<" SemID:"<<(int)sema_<<" errno:"<, 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()< 0; + + status = semGive(waiters_lock_); + + DBG_ASSERT(assert(status == OK)); + + if(status != OK) + { + DBG_TRACE(cout<<"Exception: omni_condition::signal"<mutexID<<" tid:"<<(int)taskIdSelf()< must be locked before this call is made. + // This is needed to ensure that and 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"< 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 held. + have_waiters = 1; + } + + status = semGive(waiters_lock_); + + DBG_ASSERT(assert(status == OK)); + + if(status != OK) + { + DBG_TRACE(cout<<"Exception: omni_condition::signal"<id()<<" SemID:"<<(int)sema_<<" errno:"<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 "<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 "<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 "<id()<<" detached "<detached<<" return value "<<(int)return_value<detached) + delete me; + } + else + DBG_TRACE(cout<<"omni_thread::exit: called with a non-omnithread. Exit quietly."<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