first pass at new ipc

This commit is contained in:
David Rose 2002-08-09 22:58:13 +00:00
parent d757224ff8
commit 58b5397d87
87 changed files with 2056 additions and 4854 deletions

View File

@ -22,7 +22,7 @@
#define LOCAL_LIBS downloader event ipc express pandabase
#define LOCAL_LIBS downloader event express pandabase
#define OTHER_LIBS dtoolconfig dtool
#if $[LINK_IN_GL]

View File

@ -4,7 +4,7 @@
#begin lib_target
#define TARGET device
#define LOCAL_LIBS \
dgraph display gobj gsgbase ipc mathutil linmath putil
dgraph display gobj gsgbase mathutil linmath putil
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx

View File

@ -34,7 +34,7 @@ ClientBase() {
_last_poll_frame = 0;
_cs = CS_default;
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
_client_thread = (thread *)NULL;
_shutdown = false;
#endif
@ -60,7 +60,7 @@ ClientBase::
}
}
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
if (_forked) {
_shutdown = true;
@ -84,7 +84,7 @@ ClientBase::
////////////////////////////////////////////////////////////////////
bool ClientBase::
fork_asynchronous_thread(double poll_time) {
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
if (_forked) {
device_cat.error()
<< "Attempt to fork client thread twice.\n";
@ -202,7 +202,7 @@ do_poll() {
_last_poll_time = global_clock->get_frame_time();
}
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
////////////////////////////////////////////////////////////////////
// Function: ClientBase::st_callback
// Access: Private, static
@ -239,4 +239,4 @@ callback() {
ipc_traits::sleep(0, _sleep_time);
}
}
#endif // HAVE_IPC
#endif // OLD_HAVE_IPC

View File

@ -31,7 +31,7 @@
#include "pointerTo.h"
#include "coordinateSystem.h"
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
#include "ipc_thread.h"
#endif
@ -87,7 +87,7 @@ private:
int _last_poll_frame;
CoordinateSystem _cs;
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
int _sleep_time;
thread *_client_thread;
bool _shutdown;

View File

@ -78,7 +78,7 @@ get_device_name() const {
////////////////////////////////////////////////////////////////////
INLINE void ClientDevice::
lock() {
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
_lock.lock();
#endif
}
@ -92,7 +92,7 @@ lock() {
////////////////////////////////////////////////////////////////////
INLINE void ClientDevice::
unlock() {
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
_lock.unlock();
#endif
}

View File

@ -23,7 +23,7 @@
#include <typedReferenceCount.h>
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
#include <ipc_mutex.h>
#endif
@ -64,7 +64,7 @@ private:
string _device_name;
bool _is_connected;
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
mutex _lock;
#endif

View File

@ -1,7 +1,7 @@
#define LOCAL_LIBS event ipc express pandabase
#define LOCAL_LIBS event express pandabase
#define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \
dtoolutil:c dtoolbase:c dtool:m
#define USE_PACKAGES zlib ipc net
#define USE_PACKAGES zlib net
#begin lib_target
#define TARGET downloader

View File

@ -43,7 +43,7 @@ AsyncUtility(float frequency) : _frequency(frequency) {
_threaded = false;
_threads_enabled = true;
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
_request_cond = new condition_variable(_lock);
#endif
}
@ -55,7 +55,7 @@ AsyncUtility(float frequency) : _frequency(frequency) {
////////////////////////////////////////////////////////////////////
AsyncUtility::
~AsyncUtility() {
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
delete _request_cond;
#endif
}
@ -67,7 +67,7 @@ AsyncUtility::
////////////////////////////////////////////////////////////////////
void AsyncUtility::
create_thread(void) {
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
if (_threaded == false && _threads_enabled == true) {
downloader_cat.debug()
<< "AsyncUtility::create_thread()" << endl;
@ -84,7 +84,7 @@ create_thread(void) {
////////////////////////////////////////////////////////////////////
void AsyncUtility::
destroy_thread(void) {
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
if (_threaded == false)
return;
@ -116,7 +116,7 @@ destroy_thread(void) {
////////////////////////////////////////////////////////////////////
void* AsyncUtility::
st_callback(void *arg) {
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
nassertr(arg != NULL, NULL);
((AsyncUtility *)arg)->callback();
#endif
@ -131,7 +131,7 @@ st_callback(void *arg) {
////////////////////////////////////////////////////////////////////
void AsyncUtility::
callback(void) {
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
while (process_request()) {
// Sleep until a signal arrives
_lock.lock();
@ -148,7 +148,7 @@ callback(void) {
////////////////////////////////////////////////////////////////////
void AsyncUtility::
nap(void) const {
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
#ifdef WIN32
_sleep((DWORD)(1000 * _frequency));
#else
@ -157,5 +157,5 @@ nap(void) const {
tv.tv_usec = (long)(1000000 * _frequency);
select(0, NULL, NULL, NULL, &tv);
#endif
#endif // HAVE_IPC
#endif // OLD_HAVE_IPC
}

View File

@ -25,7 +25,7 @@
#include <notify.h>
#include <typedef.h>
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
#include <ipc_mutex.h>
#include <ipc_condition.h>
#include <ipc_thread.h>
@ -61,7 +61,7 @@ protected:
float _frequency;
bool _threads_enabled;
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
mutex _lock;
condition_variable *_request_cond;
thread *_thread;

View File

@ -131,7 +131,7 @@ void MultiplexStreamBuf::
add_output(MultiplexStreamBuf::BufferType buffer_type,
MultiplexStreamBuf::OutputType output_type,
ostream *out, FILE *fout, bool owns_obj) {
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
// Ensure that we have the mutex while we fiddle with the list of
// outputs.
mutex_lock m(_lock);
@ -154,7 +154,7 @@ add_output(MultiplexStreamBuf::BufferType buffer_type,
////////////////////////////////////////////////////////////////////
void MultiplexStreamBuf::
flush() {
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
mutex_lock m(_lock);
#endif
@ -169,7 +169,7 @@ flush() {
////////////////////////////////////////////////////////////////////
int MultiplexStreamBuf::
overflow(int ch) {
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
mutex_lock m(_lock);
#endif
@ -198,7 +198,7 @@ overflow(int ch) {
////////////////////////////////////////////////////////////////////
int MultiplexStreamBuf::
sync() {
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
mutex_lock m(_lock);
#endif

View File

@ -21,7 +21,7 @@
#include <pandabase.h>
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
#include <ipc_mutex.h>
#endif
@ -82,7 +82,7 @@ private:
string _line_buffer;
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
mutex _lock;
#endif
};

View File

@ -1,8 +1,6 @@
#define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \
dtoolutil:c dtoolbase:c dtool:m pystub
#define LOCAL_LIBS downloader express event ipc
//#define BUILD_DIRECTORY $[HAVE_IPC]
#define USE_PACKAGES ipc
#define LOCAL_LIBS downloader express event
#begin bin_target
#define TARGET apply_patch

View File

@ -1,4 +1,4 @@
#define LOCAL_LIBS ipc express pandabase
#define LOCAL_LIBS express pandabase
#define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \
dtoolutil:c dtoolbase:c dtool:m

View File

@ -47,7 +47,7 @@ EventQueue::
////////////////////////////////////////////////////////////////////
void EventQueue::
queue_event(CPT_Event event) {
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
mutex_lock lock(_lock);
#endif
if (_queue.full()) {

View File

@ -26,7 +26,7 @@
#include <circBuffer.h>
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
#include <ipc_mutex.h>
#endif
@ -61,7 +61,7 @@ protected:
static void make_global_event_queue();
static EventQueue *_global_event_queue;
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
mutex _lock;
#endif
};

View File

@ -9,6 +9,9 @@
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx
#define SOURCES \
atomicAdjustDummyImpl.h atomicAdjustDummyImpl.I atomicAdjust.h \
atomicAdjust.I atomicAdjustImpl.h atomicAdjustNsprImpl.h \
atomicAdjustNsprImpl.I \
bigEndian.h buffer.I buffer.h \
checksumHashGenerator.I checksumHashGenerator.h circBuffer.I \
circBuffer.h clockObject.I clockObject.h config_express.h \
@ -25,7 +28,10 @@
memoryUsage.I memoryUsage.h \
memoryUsagePointerCounts.I memoryUsagePointerCounts.h \
memoryUsagePointers.I memoryUsagePointers.h \
multifile.I multifile.h namable.I \
multifile.I multifile.h \
mutexDummyImpl.h mutexDummyImpl.I mutex.h mutexHolder.h \
mutexHolder.I mutex.I mutexImpl.h mutexNsprImpl.h mutexNsprImpl.I \
namable.I \
namable.h nativeNumericData.I nativeNumericData.h \
numeric_types.h \
ordered_vector.h ordered_vector.I ordered_vector.T \
@ -35,8 +41,11 @@
pta_uchar.h referenceCount.I referenceCount.h \
register_type.I register_type.h \
reversedNumericData.I reversedNumericData.h \
selectIpcImpl.h \
streamReader.I streamReader.h streamWriter.I streamWriter.h \
subStream.I subStream.h subStreamBuf.h \
threadDummyImpl.h threadDummyImpl.I thread.h thread.I threadImpl.h \
threadNsprImpl.h threadNsprImpl.I threadPriority.h \
tokenBoard.I \
tokenBoard.h trueClock.I trueClock.h typeHandle.I \
typeHandle.h typedObject.I typedObject.h \
@ -56,6 +65,7 @@
patchfile.cxx patchfile.h ]
#define INCLUDED_SOURCES \
atomicAdjust.cxx atomicAdjustDummyImpl.cxx atomicAdjustNsprImpl.cxx \
buffer.cxx checksumHashGenerator.cxx clockObject.cxx \
config_express.cxx datagram.cxx datagramGenerator.cxx \
datagramIterator.cxx \
@ -63,7 +73,9 @@
get_config_path.cxx \
hashGeneratorBase.cxx hashVal.cxx indent.cxx \
memoryInfo.cxx memoryUsage.cxx memoryUsagePointerCounts.cxx \
memoryUsagePointers.cxx multifile.cxx namable.cxx \
memoryUsagePointers.cxx multifile.cxx \
mutex.cxx mutexHolder.cxx mutexDummyImpl.cxx mutexNsprImpl.cxx \
namable.cxx \
nativeNumericData.cxx \
ordered_vector.cxx \
profileTimer.cxx \
@ -71,6 +83,7 @@
reversedNumericData.cxx \
streamReader.cxx streamWriter.cxx \
subStream.cxx subStreamBuf.cxx \
thread.cxx threadDummyImpl.cxx threadNsprImpl.cxx \
trueClock.cxx typeHandle.cxx \
typedObject.cxx typedReferenceCount.cxx \
typeRegistry.cxx typeRegistryNode.cxx vector_uchar.cxx \
@ -81,6 +94,9 @@
zStream.cxx zStreamBuf.cxx
#define INSTALL_HEADERS \
atomicAdjustDummyImpl.h atomicAdjustDummyImpl.I atomicAdjust.h \
atomicAdjust.I atomicAdjustImpl.h atomicAdjustNsprImpl.h \
atomicAdjustNsprImpl.I \
bigEndian.h buffer.I buffer.h checksumHashGenerator.I \
checksumHashGenerator.h circBuffer.I circBuffer.h clockObject.I \
clockObject.h config_express.h datagram.I datagram.h \
@ -94,7 +110,10 @@
littleEndian.h memoryInfo.I memoryInfo.h memoryUsage.I \
memoryUsage.h memoryUsagePointerCounts.I \
memoryUsagePointerCounts.h memoryUsagePointers.I \
memoryUsagePointers.h multifile.I multifile.h namable.I namable.h \
memoryUsagePointers.h multifile.I multifile.h \
mutexDummyImpl.h mutexDummyImpl.I mutex.h mutexHolder.h \
mutexHolder.I mutex.I mutexImpl.h mutexNsprImpl.h mutexNsprImpl.I \
namable.I namable.h \
nativeNumericData.I nativeNumericData.h numeric_types.h \
ordered_vector.h ordered_vector.I ordered_vector.T \
patchfile.I patchfile.h pointerTo.I pointerTo.h \
@ -102,8 +121,11 @@
profileTimer.h pta_uchar.h referenceCount.I referenceCount.h \
register_type.I register_type.h \
reversedNumericData.I reversedNumericData.h \
selectIpcImpl.h \
streamReader.I streamReader.h streamWriter.I streamWriter.h \
subStream.I subStream.h subStreamBuf.h \
threadDummyImpl.h threadDummyImpl.I thread.h thread.I threadImpl.h \
threadNsprImpl.h threadNsprImpl.I threadPriority.h \
tokenBoard.I \
tokenBoard.h trueClock.I trueClock.h typeHandle.I typeHandle.h \
typedObject.I typedObject.h typedReferenceCount.I \
@ -158,3 +180,15 @@
#end test_bin_target
#endif
#begin test_bin_target
#define TARGET test_threaddata
#define LOCAL_LIBS $[LOCAL_LIBS] express
#define OTHER_LIBS dtoolutil:c dtool:m pystub
#define SOURCES \
test_threaddata.cxx
#end test_bin_target

View File

@ -0,0 +1,51 @@
// Filename: atomicAdjust.I
// Created by: drose (09Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: AtomicAdjust::inc
// Access: Public, Static
// Description: Atomically increments the indicated variable and
// returns the new value.
////////////////////////////////////////////////////////////////////
INLINE int AtomicAdjust::
inc(int &var) {
return AtomicAdjustImpl::inc(var);
}
////////////////////////////////////////////////////////////////////
// Function: AtomicAdjust::dec
// Access: Public, Static
// Description: Atomically decrements the indicated variable and
// returns the new value.
////////////////////////////////////////////////////////////////////
INLINE int AtomicAdjust::
dec(int &var) {
return AtomicAdjustImpl::dec(var);
}
////////////////////////////////////////////////////////////////////
// Function: AtomicAdjust::set
// Access: Public, Static
// Description: Atomically changes the indicated variable and
// returns the original value.
////////////////////////////////////////////////////////////////////
INLINE int AtomicAdjust::
set(int &var, int new_value) {
return AtomicAdjustImpl::set(var, new_value);
}

View File

@ -0,0 +1,19 @@
// Filename: atomicAdjust.cxx
// Created by: drose (09Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "atomicAdjust.h"

View File

@ -0,0 +1,41 @@
// Filename: atomicAdjust.h
// Created by: drose (09Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef ATOMICADJUST_H
#define ATOMICADJUST_H
#include "pandabase.h"
#include "atomicAdjustImpl.h"
////////////////////////////////////////////////////////////////////
// Class : AtomicAdjust
// Description : A suite of functions to atomically adjust a numeric
// value. Some platforms require a bit more work than
// others to guarantee that a multibyte value is changed
// in one atomic operation.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA AtomicAdjust {
public:
INLINE static int inc(int &var);
INLINE static int dec(int &var);
INLINE static int set(int &var, int new_value);
};
#include "atomicAdjust.I"
#endif

View File

@ -0,0 +1,53 @@
// Filename: atomicAdjustDummyImpl.I
// Created by: drose (09Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: AtomicAdjustDummyImpl::inc
// Access: Public, Static
// Description: Atomically increments the indicated variable and
// returns the new value.
////////////////////////////////////////////////////////////////////
INLINE int AtomicAdjustDummyImpl::
inc(int &var) {
return ++var;
}
////////////////////////////////////////////////////////////////////
// Function: AtomicAdjustDummyImpl::dec
// Access: Public, Static
// Description: Atomically decrements the indicated variable and
// returns the new value.
////////////////////////////////////////////////////////////////////
INLINE int AtomicAdjustDummyImpl::
dec(int &var) {
return --var;
}
////////////////////////////////////////////////////////////////////
// Function: AtomicAdjustDummyImpl::set
// Access: Public, Static
// Description: Atomically changes the indicated variable and
// returns the original value.
////////////////////////////////////////////////////////////////////
INLINE int AtomicAdjustDummyImpl::
set(int &var, int new_value) {
int orig_value = var;
var = new_value;
return orig_value;
}

View File

@ -0,0 +1,25 @@
// Filename: atomicAdjustDummyImpl.cxx
// Created by: drose (09Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "selectIpcImpl.h"
#ifdef IPC_DUMMY_IMPL
#include "atomicAdjustDummyImpl.h"
#endif // IPC_DUMMY_IMPL

View File

@ -0,0 +1,45 @@
// Filename: atomicAdjustDummyImpl.h
// Created by: drose (09Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef ATOMICADJUSTDUMMYIMPL_H
#define ATOMICADJUSTDUMMYIMPL_H
#include "pandabase.h"
#include "selectIpcImpl.h"
#ifdef IPC_DUMMY_IMPL
#include "notify.h"
////////////////////////////////////////////////////////////////////
// Class : AtomicAdjustDummyImpl
// Description : A trivial implementation for atomic adjustments for
// systems that don't require multiprogramming, and
// therefore don't require special atomic operations.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA AtomicAdjustDummyImpl {
public:
INLINE static int inc(int &var);
INLINE static int dec(int &var);
INLINE static int set(int &var, int new_value);
};
#include "atomicAdjustDummyImpl.I"
#endif // IPC_DUMMY_IMPL
#endif

View File

@ -1,5 +1,5 @@
// Filename: ipc_atomics.h
// Created by: frang (10Feb00)
// Filename: atomicAdjustImpl.h
// Created by: drose (09Aug02)
//
////////////////////////////////////////////////////////////////////
//
@ -16,23 +16,22 @@
//
////////////////////////////////////////////////////////////////////
#ifndef __IPC_ATOMICS_H__
#define __IPC_ATOMICS_H__
#ifndef ATOMICADJUSTIMPL_H
#define ATOMICADJUSTIMPL_H
#include <pandabase.h>
#include "pandabase.h"
#include "selectIpcImpl.h"
#include "ipc_traits.h"
#if defined(IPC_DUMMY_IMPL)
INLINE int set_atomic(int& var, int val) {
return ipc_traits::set_atomic(var, val);
}
#include "atomicAdjustDummyImpl.h"
typedef AtomicAdjustDummyImpl AtomicAdjustImpl;
INLINE int inc_atomic(int& var) {
return ipc_traits::inc_atomic(var);
}
#elif defined(IPC_NSPR_IMPL)
INLINE int dec_atomic(int& var) {
return ipc_traits::dec_atomic(var);
}
#include "atomicAdjustNsprImpl.h"
typedef AtomicAdjustNsprImpl AtomicAdjustImpl;
#endif /* __IPC_ATOMICS_H__ */
#endif
#endif

View File

@ -0,0 +1,51 @@
// Filename: atomicAdjustNsprImpl.I
// Created by: drose (09Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: AtomicAdjustNsprImpl::inc
// Access: Public, Static
// Description: Atomically increments the indicated variable and
// returns the new value.
////////////////////////////////////////////////////////////////////
INLINE int AtomicAdjustNsprImpl::
inc(int &var) {
return PR_AtomicIncrement(&var);
}
////////////////////////////////////////////////////////////////////
// Function: AtomicAdjustNsprImpl::dec
// Access: Public, Static
// Description: Atomically decrements the indicated variable and
// returns the new value.
////////////////////////////////////////////////////////////////////
INLINE int AtomicAdjustNsprImpl::
dec(int &var) {
return PR_AtomicDecrement(&var);
}
////////////////////////////////////////////////////////////////////
// Function: AtomicAdjustNsprImpl::set
// Access: Public, Static
// Description: Atomically changes the indicated variable and
// returns the original value.
////////////////////////////////////////////////////////////////////
INLINE int AtomicAdjustNsprImpl::
set(int &var, int new_value) {
return PR_AtomicSet(&var, new_value);
}

View File

@ -0,0 +1,25 @@
// Filename: atomicAdjustNsprImpl.cxx
// Created by: drose (09Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "selectIpcImpl.h"
#ifdef IPC_NSPR_IMPL
#include "atomicAdjustNsprImpl.h"
#endif // IPC_NSPR_IMPL

View File

@ -0,0 +1,46 @@
// Filename: atomicAdjustNsprImpl.h
// Created by: drose (09Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef ATOMICADJUSTNSPRIMPL_H
#define ATOMICADJUSTNSPRIMPL_H
#include "pandabase.h"
#include "selectIpcImpl.h"
#ifdef IPC_NSPR_IMPL
#include "notify.h"
#include <pratom.h>
////////////////////////////////////////////////////////////////////
// Class : AtomicAdjustNsprImpl
// Description : Uses NSPR to implement atomic adjustments.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA AtomicAdjustNsprImpl {
public:
INLINE static int inc(int &var);
INLINE static int dec(int &var);
INLINE static int set(int &var, int new_value);
};
#include "atomicAdjustNsprImpl.I"
#endif // IPC_NSPR_IMPL
#endif

View File

@ -33,6 +33,7 @@
ConfigureDef(config_express);
NotifyCategoryDef(express, "");
NotifyCategoryDef(ipc, "");
extern void init_system_type_handles();

View File

@ -25,6 +25,7 @@
ConfigureDecl(config_express, EXPCL_PANDAEXPRESS, EXPTP_PANDAEXPRESS);
NotifyCategoryDecl(express, EXPCL_PANDAEXPRESS, EXPTP_PANDAEXPRESS);
NotifyCategoryDecl(ipc, EXPCL_PANDAEXPRESS, EXPTP_PANDAEXPRESS);
// Actually, we can't determine this config variable the normal way,
// because we must be able to access it at static init time. Instead

View File

@ -1,3 +1,6 @@
#include "atomicAdjust.cxx"
#include "atomicAdjustDummyImpl.cxx"
#include "atomicAdjustNsprImpl.cxx"
#include "buffer.cxx"
#include "checksumHashGenerator.cxx"
#include "clockObject.cxx"
@ -17,6 +20,10 @@
#include "memoryUsagePointerCounts.cxx"
#include "memoryUsagePointers.cxx"
#include "multifile.cxx"
#include "mutex.cxx"
#include "mutexHolder.cxx"
#include "mutexDummyImpl.cxx"
#include "mutexNsprImpl.cxx"
#include "namable.cxx"
#include "nativeNumericData.cxx"
#include "ordered_vector.cxx"

View File

@ -4,6 +4,9 @@
#include "streamWriter.cxx"
#include "subStream.cxx"
#include "subStreamBuf.cxx"
#include "thread.cxx"
#include "threadDummyImpl.cxx"
#include "threadNsprImpl.cxx"
#include "trueClock.cxx"
#include "typeHandle.cxx"
#include "typedObject.cxx"

83
panda/src/express/mutex.I Normal file
View File

@ -0,0 +1,83 @@
// Filename: mutex.I
// Created by: drose (08Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: Mutex::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE Mutex::
Mutex() {
}
////////////////////////////////////////////////////////////////////
// Function: Mutex::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE Mutex::
~Mutex() {
}
////////////////////////////////////////////////////////////////////
// Function: Mutex::Copy Constructor
// Access: Private
// Description: Do not attempt to copy mutexes.
////////////////////////////////////////////////////////////////////
INLINE Mutex::
Mutex(const Mutex &copy) {
nassertv(false);
}
////////////////////////////////////////////////////////////////////
// Function: Mutex::Copy Assignment Operator
// Access: Private
// Description: Do not attempt to copy mutexes.
////////////////////////////////////////////////////////////////////
INLINE void Mutex::
operator = (const Mutex &copy) {
nassertv(false);
}
////////////////////////////////////////////////////////////////////
// Function: Mutex::lock
// Access: Public
// Description: Grabs the mutex if it is available. If it is not
// available, blocks until it becomes available, then
// grabs it. In either case, the function does not
// return until the mutex is held; you should then call
// unlock().
//
// Also see MutexHolder.
////////////////////////////////////////////////////////////////////
INLINE void Mutex::
lock() {
_impl.lock();
}
////////////////////////////////////////////////////////////////////
// Function: Mutex::release
// Access: Public
// Description: Releases the mutex. It is an error to call this if
// the mutex was not already locked.
////////////////////////////////////////////////////////////////////
INLINE void Mutex::
release() {
_impl.release();
}

View File

@ -1,5 +1,5 @@
// Filename: ipc_file.I
// Created by: jason (07Jun00)
// Filename: mutex.cxx
// Created by: drose (08Aug02)
//
////////////////////////////////////////////////////////////////////
//
@ -15,3 +15,5 @@
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "mutex.h"

51
panda/src/express/mutex.h Normal file
View File

@ -0,0 +1,51 @@
// Filename: mutex.h
// Created by: cary (16Sep98)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef MUTEX_H
#define MUTEX_H
#include "pandabase.h"
#include "mutexImpl.h"
#include "notify.h"
////////////////////////////////////////////////////////////////////
// Class : Mutex
// Description : A standard mutex, or mutual exclusion lock. Only one
// thread can hold ("lock") a mutex at any given time;
// other threads trying to grab the mutex will block
// until the holding thread releases it.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA Mutex {
public:
INLINE Mutex();
INLINE ~Mutex();
private:
INLINE Mutex(const Mutex &copy);
INLINE void operator = (const Mutex &copy);
public:
INLINE void lock();
INLINE void release();
private:
MutexImpl _impl;
};
#include "mutex.I"
#endif

View File

@ -0,0 +1,66 @@
// Filename: mutexDummyImpl.I
// Created by: drose (08Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: MutexDummyImpl::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE MutexDummyImpl::
MutexDummyImpl() {
#ifndef NDEBUG
_lock_count = 0;
#endif
}
////////////////////////////////////////////////////////////////////
// Function: MutexDummyImpl::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE MutexDummyImpl::
~MutexDummyImpl() {
nassertv(_lock_count == 0);
}
////////////////////////////////////////////////////////////////////
// Function: MutexDummyImpl::lock
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void MutexDummyImpl::
lock() {
#ifndef NDEBUG
_lock_count++;
nassertv(_lock_count == 1);
#endif
}
////////////////////////////////////////////////////////////////////
// Function: MutexDummyImpl::release
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void MutexDummyImpl::
release() {
#ifndef NDEBUG
_lock_count--;
nassertv(_lock_count == 0);
#endif
}

View File

@ -0,0 +1,25 @@
// Filename: mutexDummyImpl.cxx
// Created by: drose (08Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "selectIpcImpl.h"
#ifdef IPC_DUMMY_IMPL
#include "mutexDummyImpl.h"
#endif // IPC_DUMMY_IMPL

View File

@ -0,0 +1,53 @@
// Filename: mutexDummyImpl.h
// Created by: drose (08Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef MUTEXDUMMYIMPL_H
#define MUTEXDUMMYIMPL_H
#include "pandabase.h"
#include "selectIpcImpl.h"
#ifdef IPC_DUMMY_IMPL
#include "notify.h"
////////////////////////////////////////////////////////////////////
// Class : MutexDummyImpl
// Description : A fake mutex implementation for single-threaded
// applications that don't need any synchronization
// control. This does nothing but assert that the same
// process does not try to grab the mutex twice.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA MutexDummyImpl {
public:
INLINE MutexDummyImpl();
INLINE ~MutexDummyImpl();
INLINE void lock();
INLINE void release();
private:
#ifndef NDEBUG
int _lock_count;
#endif
};
#include "mutexDummyImpl.I"
#endif // IPC_DUMMY_IMPL
#endif

View File

@ -0,0 +1,85 @@
// Filename: mutexHolder.I
// Created by: drose (09Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: MutexHolder::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE MutexHolder::
MutexHolder(Mutex &mutex) {
#ifdef HAVE_IPC
_mutex = &mutex;
_mutex->lock();
#endif
}
////////////////////////////////////////////////////////////////////
// Function: MutexHolder::Constructor
// Access: Public
// Description: If the MutexHolder constructor is given a pointer to
// a Mutex object (instead of an actual object), it will
// first check to see if the pointer is NULL, and
// allocate a new Mutex if it is. This is intended as a
// convenience for functions that may need to reference
// a Mutex at static init time, when it is impossible to
// guarantee ordering of initializers.
////////////////////////////////////////////////////////////////////
INLINE MutexHolder::
MutexHolder(Mutex *&mutex) {
#ifdef HAVE_IPC
if (mutex == (Mutex *)NULL) {
mutex = new Mutex;
}
_mutex = mutex;
_mutex->lock();
#endif
}
////////////////////////////////////////////////////////////////////
// Function: MutexHolder::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE MutexHolder::
~MutexHolder() {
#ifdef HAVE_IPC
_mutex->release();
#endif
}
////////////////////////////////////////////////////////////////////
// Function: MutexHolder::Copy Constructor
// Access: Private
// Description: Do not attempt to copy MutexHolders.
////////////////////////////////////////////////////////////////////
INLINE MutexHolder::
MutexHolder(const MutexHolder &copy) {
nassertv(false);
}
////////////////////////////////////////////////////////////////////
// Function: MutexHolder::Copy Assignment Operator
// Access: Private
// Description: Do not attempt to copy MutexHolders.
////////////////////////////////////////////////////////////////////
INLINE void MutexHolder::
operator = (const MutexHolder &copy) {
nassertv(false);
}

View File

@ -0,0 +1,19 @@
// Filename: mutexHolder.cxx
// Created by: drose (09Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "mutexHolder.h"

View File

@ -0,0 +1,50 @@
// Filename: mutexHolder.h
// Created by: drose (09Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef MUTEXHOLDER_H
#define MUTEXHOLDER_H
#include "pandabase.h"
#include "mutex.h"
////////////////////////////////////////////////////////////////////
// Class : MutexHolder
// Description : A lightweight C++ object whose constructor calls
// lock() and whose destructor calls release() on a
// mutex. It is a C++ convenience wrapper to call
// release() automatically when a block exits (for
// instance, on return).
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA MutexHolder {
public:
INLINE MutexHolder(Mutex &mutex);
INLINE MutexHolder(Mutex *&mutex);
INLINE ~MutexHolder();
private:
INLINE MutexHolder(const MutexHolder &copy);
INLINE void operator = (const MutexHolder &copy);
private:
#ifdef HAVE_IPC
Mutex *_mutex;
#endif
};
#include "mutexHolder.I"
#endif

View File

@ -1,5 +1,5 @@
// Filename: ipc_nt_traits.cxx
// Created by: mike (23Oct98)
// Filename: mutexImpl.h
// Created by: drose (08Aug02)
//
////////////////////////////////////////////////////////////////////
//
@ -16,15 +16,25 @@
//
////////////////////////////////////////////////////////////////////
#ifdef WIN32_VC
#ifndef MUTEXIMPL_H
#define MUTEXIMPL_H
#include "ipc_nt_traits.h"
#include "pandabase.h"
#include "selectIpcImpl.h"
const int ipc_traits::days_in_preceeding_months[12] = { 0, 31, 59, 90,
120, 151, 181, 212,
243, 273, 304, 334 };
const int ipc_traits::days_in_preceeding_months_leap[12] = { 0, 31, 60,
91, 121, 152, 182, 213,
244, 274, 305, 335 };
#if defined(IPC_DUMMY_IMPL)
#include "mutexDummyImpl.h"
typedef MutexDummyImpl MutexImpl;
#elif defined(IPC_NSPR_IMPL)
#include "mutexNsprImpl.h"
typedef MutexNsprImpl MutexImpl;
#endif
#endif

View File

@ -0,0 +1,59 @@
// Filename: mutexNsprImpl.I
// Created by: drose (08Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: MutexNsprImpl::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE MutexNsprImpl::
MutexNsprImpl() {
_lock = PR_NewLock();
}
////////////////////////////////////////////////////////////////////
// Function: MutexNsprImpl::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE MutexNsprImpl::
~MutexNsprImpl() {
PR_DestroyLock(_lock);
}
////////////////////////////////////////////////////////////////////
// Function: MutexNsprImpl::lock
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void MutexNsprImpl::
lock() {
PR_Lock(_lock);
}
////////////////////////////////////////////////////////////////////
// Function: MutexNsprImpl::release
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void MutexNsprImpl::
release() {
int status = PR_Unlock(_lock);
nassertv(status == PR_SUCCESS);
}

View File

@ -0,0 +1,25 @@
// Filename: mutexNsprImpl.cxx
// Created by: drose (09Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "selectIpcImpl.h"
#ifdef IPC_NSPR_IMPL
#include "mutexNsprImpl.h"
#endif // IPC_NSPR_IMPL

View File

@ -0,0 +1,51 @@
// Filename: mutexNsprImpl.h
// Created by: drose (08Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef MUTEXNSPRIMPL_H
#define MUTEXNSPRIMPL_H
#include "pandabase.h"
#include "selectIpcImpl.h"
#ifdef IPC_NSPR_IMPL
#include "notify.h"
#include <prlock.h>
////////////////////////////////////////////////////////////////////
// Class : MutexNsprImpl
// Description : Uses NSPR to implement a mutex.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA MutexNsprImpl {
public:
INLINE MutexNsprImpl();
INLINE ~MutexNsprImpl();
INLINE void lock();
INLINE void release();
private:
PRLock *_lock;
};
#include "mutexNsprImpl.I"
#endif // IPC_NSPR_IMPL
#endif

View File

@ -94,25 +94,6 @@ operator = (const ReferenceCount &) {
////////////////////////////////////////////////////////////////////
INLINE ReferenceCount::
~ReferenceCount() {
prepare_delete();
#ifdef DO_MEMORY_USAGE
MemoryUsage::remove_pointer(this);
#endif
}
////////////////////////////////////////////////////////////////////
// Function: ReferenceCount::prepare_delete
// Access: Public
// Description: This function is called by the ReferenceCount
// destructor to check on all of the numbers and make
// sure it's all right to delete the object. Normally
// it will never be called explicitly elsewhere, except
// maybe in unref_delete() to simulate deleting the node
// without actually deleting it, when we want to test
// ref count integrities.
////////////////////////////////////////////////////////////////////
INLINE void ReferenceCount::
prepare_delete() {
nassertv(this != NULL);
// If this assertion fails, we're trying to delete an object that
@ -138,28 +119,16 @@ prepare_delete() {
// all--onto a locally allocated one.
nassertv(_ref_count == 0);
#ifndef NDEBUG
// Ok, all clear to delete. Now set the reference count to -100,
// so we'll have a better chance of noticing if we happen to have
// a stray pointer to it still out there.
_ref_count = -100;
}
#endif
////////////////////////////////////////////////////////////////////
// Function: ReferenceCount::unref_consider_delete
// Access: Public
// Description: This function is called by the global unref_delete()
// function. This function unrefs the pointer and
// returns true if it should be deleted (i.e. the count
// has gone to zero), or false otherwise. It doesn't
// delete itself because (a) a method cannot safely
// delete this, and (b) we don't have a virtual
// destructor anyway. The decision of whether to delete
// is left up to unref_delete().
////////////////////////////////////////////////////////////////////
INLINE bool ReferenceCount::
unref_consider_delete() {
unref();
return (get_ref_count() == 0);
#ifdef DO_MEMORY_USAGE
MemoryUsage::remove_pointer(this);
#endif
}
////////////////////////////////////////////////////////////////////
@ -169,9 +138,9 @@ unref_consider_delete() {
////////////////////////////////////////////////////////////////////
INLINE int ReferenceCount::
get_ref_count() const {
#ifndef NDEBUG
#ifndef NDEBUG
test_ref_count_integrity();
#endif
#endif
return _ref_count;
}
@ -190,10 +159,12 @@ get_ref_count() const {
// with the object. An object might be const in other
// ways, but we still need to accurately count the
// number of references to it.
//
// The return value is the new reference count.
////////////////////////////////////////////////////////////////////
INLINE void ReferenceCount::
INLINE int ReferenceCount::
ref() const {
nassertv(this != NULL);
nassertr(this != NULL, 0);
// If this assertion fails, we're trying to ref a pointer that was
// just deleted. Probably you used a real pointer instead of a
@ -201,30 +172,14 @@ ref() const {
// PointerTo went out of scope. Either that, or you forgot to
// define a copy constructor for a class that contains
// PointerTo's.
nassertv(_ref_count != -100);
nassertr(_ref_count != -100, 0);
// If this assertion fails, the reference counts are all screwed
// up altogether. Maybe some errant code stomped all over memory
// somewhere.
nassertv(_ref_count >= 0);
nassertr(_ref_count >= 0, 0);
#if 0
// This is an SGI-specific hack. Maybe this isn't a valid test at
// all. This is supposed to fail if the 'this' pointer is on the
// stack, instead of on the heap--I assume if the first two hex
// digits of the pointer of 0x7f it's on the stack, possibly a bad
// assumption. In any case, if you ref-count a pointer on the
// stack, you just goofed. Don't assign a PointerTo to refer to
// any local variables!
nassertv(((long)this & 0xff000000) != 0x7f000000);
#endif
((ReferenceCount *)this)->_ref_count++;
// If this assertion fails, we have just wrapped! Either there
// are actually 2^32 pointers to this thing somewhere, or
// something is really screwy.
nassertv(_ref_count > 0);
return AtomicAdjust::inc(((ReferenceCount *)this)->_ref_count);
}
////////////////////////////////////////////////////////////////////
@ -233,7 +188,10 @@ ref() const {
// Description: Explicitly decrements the reference count. Note that
// the object will not be implicitly deleted by unref()
// simply because the reference count drops to zero.
// However, see the helper function unref_delete().
// (Having a member function delete itself is
// problematic; plus, we don't have a virtual destructor
// anyway.) However, see the helper function
// unref_delete().
//
// User code should avoid using ref() and unref()
// directly, which can result in missed reference
@ -246,10 +204,12 @@ ref() const {
// with the object. An object might be const in other
// ways, but we still need to accurately count the
// number of references to it.
//
// The return value is the new reference count.
////////////////////////////////////////////////////////////////////
INLINE void ReferenceCount::
INLINE int ReferenceCount::
unref() const {
nassertv(this != NULL);
nassertr(this != NULL, false);
// If this assertion fails, we're trying to unref a pointer that
// was just deleted. Probably you used a real pointer instead of
@ -257,18 +217,18 @@ unref() const {
// PointerTo went out of scope. Either that, or you forgot to
// define a copy constructor for a class that contains
// PointerTo's.
nassertv(_ref_count != -100);
nassertr(_ref_count != -100, false);
// If this assertion fails, the reference counts are all screwed
// up altogether. Maybe some errant code stomped all over memory
// somewhere.
nassertv(_ref_count >= 0);
nassertr(_ref_count >= 0, false);
// If this assertion fails, you tried to unref an object with a
// zero reference count. Are you using ref() and unref()
// directly? Are you sure you can't use PointerTo's?
nassertv(_ref_count > 0);
((ReferenceCount *)this)->_ref_count--;
nassertr(_ref_count > 0, false);
return AtomicAdjust::dec(((ReferenceCount *)this)->_ref_count);
}
@ -280,7 +240,7 @@ unref() const {
////////////////////////////////////////////////////////////////////
INLINE void ReferenceCount::
test_ref_count_integrity() const {
#ifndef NDEBUG
#ifndef NDEBUG
nassertv(this != NULL);
// If this assertion fails, we're trying to access a pointer that
@ -295,7 +255,7 @@ test_ref_count_integrity() const {
// up altogether. Maybe some errant code stomped all over memory
// somewhere.
nassertv(_ref_count >= 0);
#endif
#endif
}
////////////////////////////////////////////////////////////////////
@ -311,7 +271,7 @@ test_ref_count_integrity() const {
template<class RefCountType>
INLINE void
unref_delete(RefCountType *ptr) {
if (((ReferenceCount *)ptr)->unref_consider_delete()) {
if (((ReferenceCount *)ptr)->unref() == 0) {
#ifndef NDEBUG
if (get_leak_memory()) {
// In leak-memory mode, we don't actually delete the pointer,
@ -319,9 +279,9 @@ unref_delete(RefCountType *ptr) {
// exactly the same effect as deleting it, without actually
// freeing up the memory it uses.
// Furthermore, if we have never-destruct set, we don't even
// call the destructor.
if (!get_never_destruct()) {
// Furthermore, if we have never-destruct set, we don't even
// call the destructor.
ptr->~RefCountType();
}
return;

View File

@ -24,6 +24,7 @@
#include "typedObject.h"
#include "memoryUsage.h"
#include "config_express.h"
#include "atomicAdjust.h"
#include <stdlib.h>
@ -45,16 +46,10 @@ protected:
INLINE void operator = (const ReferenceCount &);
INLINE ~ReferenceCount();
public:
// These functions are not part of the normal API, but they have to
// be public. You shouldn't generally call these directly.
INLINE void prepare_delete();
INLINE bool unref_consider_delete();
PUBLISHED:
INLINE int get_ref_count() const;
INLINE void ref() const;
INLINE void unref() const;
INLINE int ref() const;
INLINE int unref() const;
INLINE void test_ref_count_integrity() const;

View File

@ -0,0 +1,49 @@
// Filename: selectIpcImpl.h
// Created by: drose (09Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef SELECTIPCIMPL_H
#define SELECTIPCIMPL_H
#include "pandabase.h"
////////////////////////////////////////////////////////////////////
// This file decides which of the core implementations of the various
// ipc (actually, threading) implementations we should use, based on
// platform and/or available libraries.
////////////////////////////////////////////////////////////////////
#if !defined(HAVE_IPC)
// With IPC disabled, use the do-nothing implementation.
#define IPC_DUMMY_IMPL 1
#elif defined(HAVE_NSPR)
// If NSPR is available, use that.
#define IPC_NSPR_IMPL 1
#else
// This is a configuration error. For some reason, HAVE_IPC is
// defined but we don't have any way to implement it.
#error No ipc implementation defined for platform.
#endif
#endif

View File

@ -0,0 +1,90 @@
// Filename: test_threaddata.cxx
// Created by: cary (16Sep98)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "pandabase.h"
#include "thread.h"
#include "mutex.h"
#include "mutexHolder.h"
#include "pointerTo.h"
Mutex *cout_mutex = (Mutex *)NULL;
// Test forking a thread with some private data.
class ThreadWithData : public Thread {
public:
ThreadWithData(const string &name, int parameter);
virtual void thread_main();
private:
int _parameter;
};
ThreadWithData::
ThreadWithData(const string &name, int parameter) :
Thread(name),
_parameter(parameter)
{
MutexHolder holder(cout_mutex);
cout << "Creating thread " << get_name() << " with parameter " << _parameter
<< "\n";
}
void ThreadWithData::
thread_main() {
for (int i = 0; i < _parameter; i++) {
{
MutexHolder holder(cout_mutex);
cout << "Running thread " << get_name()
<< " with parameter " << _parameter
<< ", i = " << i << "\n" << flush;
Thread *thread = get_current_thread();
nassertv(thread == this);
}
Thread::sleep((double) i / 10.0);
}
}
int
main() {
cout << "main beginning.\n";
for (int i = 0; i < 10; i++) {
string name = string("thread_") + (char)(i + 'a');
PT(Thread) thread = new ThreadWithData(name, i);
if (!thread->start(TP_low, false, false)) {
MutexHolder holder(cout_mutex);
cout << "Unable to start " << name << ".\n";
} else {
MutexHolder holder(cout_mutex);
cout << "Started " << name << ", count = "
<< thread->get_ref_count() << "\n";
}
}
{
MutexHolder holder(cout_mutex);
cout << "main preparing to exit.\n";
}
Thread::prepare_for_exit();
cout << "main exiting.\n";
return 0;
}

158
panda/src/express/thread.I Normal file
View File

@ -0,0 +1,158 @@
// Filename: thread.I
// Created by: drose (08Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: Thread::Constructor
// Access: Public
// Description: Creates a new Thread object, but does not
// immediately start executing it. This gives the
// caller a chance to store it in a PT(Thread) object,
// if desired, before the thread gets a chance to
// terminate and destruct itself.
//
// Call start() to begin thread execution.
////////////////////////////////////////////////////////////////////
INLINE Thread::
Thread(const string &name) : _name(name), _impl(this) {
_started = false;
}
////////////////////////////////////////////////////////////////////
// Function: Thread::Copy Constructor
// Access: Private
// Description: Do not attempt to copy threads.
////////////////////////////////////////////////////////////////////
INLINE Thread::
Thread(const Thread &copy) : _impl(this) {
nassertv(false);
}
////////////////////////////////////////////////////////////////////
// Function: Thread::Copy Assignment Operator
// Access: Private
// Description: Do not attempt to copy threads.
////////////////////////////////////////////////////////////////////
INLINE void Thread::
operator = (const Thread &copy) {
nassertv(false);
}
////////////////////////////////////////////////////////////////////
// Function: Thread::get_name
// Access: Public
// Description: Returns the name of the thread.
////////////////////////////////////////////////////////////////////
INLINE const string &Thread::
get_name() const {
return _name;
}
////////////////////////////////////////////////////////////////////
// Function: Thread::start
// Access: Public
// Description: Starts the thread executing. It is only valid to
// call this once.
//
// The thread will begin executing its thread_main()
// function, and will terminate when thread_main()
// returns.
//
// priority is intended as a hint to the relative
// importance of this thread, and global should be set
// true if the thread will perform a lot of blocking
// I/O, or false otherwise (see the NSPR documentation
// on global vs. local threads for more on this). Both
// of these parameters may be ignored by the thread
// implementation.
//
// joinable should be set true if you intend to call
// join() to wait for the thread to terminate, or false
// if you don't care and you will never call join().
//
// The return value is true if the thread is
// successfully started, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool Thread::
start(ThreadPriority priority, bool global, bool joinable) {
nassertr(!_started, false);
_started = _impl.start(priority, global, joinable);
return _started;
}
////////////////////////////////////////////////////////////////////
// Function: Thread::join
// Access: Public
// Description: Blocks the calling process until the thread
// terminates. If the thread has already terminated,
// this returns immediately.
////////////////////////////////////////////////////////////////////
INLINE void Thread::
join() {
_impl.join();
}
////////////////////////////////////////////////////////////////////
// Function: Thread::prepare_for_exit
// Access: Public
// Description: Should be called by the main thread just before
// exiting the program, this blocks until any remaining
// thread cleanup has finished.
////////////////////////////////////////////////////////////////////
INLINE void Thread::
prepare_for_exit() {
ThreadImpl::prepare_for_exit();
}
////////////////////////////////////////////////////////////////////
// Function: Thread::get_current_thread
// Access: Public, Static
// Description: Returns a pointer to the currently-executing Thread
// object, or NULL if the main thread (or some system
// thread other than one started from the Panda
// interface) is currently executing.
////////////////////////////////////////////////////////////////////
INLINE Thread *Thread::
get_current_thread() {
return ThreadImpl::get_current_thread();
}
////////////////////////////////////////////////////////////////////
// Function: Thread::is_threading_supported
// Access: Public, Static
// Description: Returns true if a real threading library is available
// that supports threads, or false if no threading
// library is available (and Thread::start() will always
// fail).
////////////////////////////////////////////////////////////////////
INLINE bool Thread::
is_threading_supported() {
return ThreadImpl::is_threading_supported();
}
////////////////////////////////////////////////////////////////////
// Function: Thread::sleep
// Access: Public, Static
// Description: Suspends the current thread for at least the
// indicated amount of time. It might be suspended for
// longer.
////////////////////////////////////////////////////////////////////
INLINE void Thread::
sleep(double seconds) {
ThreadImpl::sleep(seconds);
}

View File

@ -0,0 +1,29 @@
// Filename: thread.cxx
// Created by: drose (08Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "thread.h"
////////////////////////////////////////////////////////////////////
// Function: Thread::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
Thread::
~Thread() {
}

View File

@ -0,0 +1,73 @@
// Filename: thread.h
// Created by: cary (16Sep98)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef THREAD_H
#define THREAD_H
#include "pandabase.h"
#include "referenceCount.h"
#include "threadPriority.h"
#include "threadImpl.h"
#include "notify.h"
////////////////////////////////////////////////////////////////////
// Class : Thread
// Description : A thread; that is, a lightweight process. This is an
// abstract base class; to use it, you must subclass
// from it and redefine thread_main().
//
// The thread itself will keep a reference count on the
// Thread object while it is running; when the thread
// returns from its root function, the Thread object
// will automatically be destructed if no other pointers
// are referencing it.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA Thread : public ReferenceCount {
public:
INLINE Thread(const string &name);
virtual ~Thread();
private:
INLINE Thread(const Thread &copy);
INLINE void operator = (const Thread &copy);
protected:
virtual void thread_main()=0;
public:
INLINE const string &get_name() const;
INLINE bool start(ThreadPriority priority, bool global, bool joinable);
INLINE void join();
INLINE static void prepare_for_exit();
INLINE static Thread *get_current_thread();
INLINE static bool is_threading_supported();
INLINE static void sleep(double seconds);
private:
bool _started;
string _name;
ThreadImpl _impl;
friend ThreadImpl;
};
#include "thread.I"
#endif

View File

@ -0,0 +1,93 @@
// Filename: threadDummyImpl.I
// Created by: drose (09Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: ThreadDummyImpl::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE ThreadDummyImpl::
ThreadDummyImpl(Thread *) {
}
////////////////////////////////////////////////////////////////////
// Function: ThreadDummyImpl::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE ThreadDummyImpl::
~ThreadDummyImpl() {
}
////////////////////////////////////////////////////////////////////
// Function: ThreadDummyImpl::start
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool ThreadDummyImpl::
start(ThreadPriority, bool, bool) {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: ThreadDummyImpl::join
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void ThreadDummyImpl::
join() {
}
////////////////////////////////////////////////////////////////////
// Function: ThreadDummyImpl::prepare_for_exit
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void ThreadDummyImpl::
prepare_for_exit() {
}
////////////////////////////////////////////////////////////////////
// Function: ThreadDummyImpl::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE Thread *ThreadDummyImpl::
get_current_thread() {
return NULL;
}
////////////////////////////////////////////////////////////////////
// Function: ThreadDummyImpl::is_threading_supported
// Access: Public, Static
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool ThreadDummyImpl::
is_threading_supported() {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: ThreadDummyImpl::sleep
// Access: Public, Static
// Description:
////////////////////////////////////////////////////////////////////
INLINE void ThreadDummyImpl::
sleep(double) {
}

View File

@ -0,0 +1,25 @@
// Filename: threadDummyImpl.cxx
// Created by: drose (09Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "selectIpcImpl.h"
#ifdef IPC_DUMMY_IMPL
#include "threadDummyImpl.h"
#endif // IPC_DUMMY_IMPL

View File

@ -0,0 +1,64 @@
// Filename: threadDummyImpl.h
// Created by: drose (09Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef THREADDUMMYIMPL_H
#define THREADDUMMYIMPL_H
#include "pandabase.h"
#include "selectIpcImpl.h"
#ifdef IPC_DUMMY_IMPL
#include "notify.h"
#include "threadPriority.h"
#include "mutex.h"
#include <prthread.h>
class Thread;
////////////////////////////////////////////////////////////////////
// Class : ThreadDummyImpl
// Description : A fake thread implementation for single-threaded
// applications. This simply fails whenever you try to
// start a thread.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA ThreadDummyImpl {
public:
INLINE ThreadDummyImpl(Thread *parent_obj);
INLINE ~ThreadDummyImpl();
INLINE bool start(ThreadPriority priority, bool global, bool joinable);
INLINE void join();
INLINE static void prepare_for_exit();
INLINE static Thread *get_current_thread();
INLINE static bool is_threading_supported();
INLINE static void sleep(double seconds);
INLINE int atomic_inc(int &var);
INLINE int atomic_dec(int &var);
INLINE int atomic_set(int &var, int new_value);
};
#include "threadDummyImpl.I"
#endif // IPC_DUMMY_IMPL
#endif

View File

@ -0,0 +1,37 @@
// Filename: threadImpl.h
// Created by: drose (09Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef THREADIMPL_H
#define THREADIMPL_H
#include "pandabase.h"
#include "selectIpcImpl.h"
#if defined(IPC_DUMMY_IMPL)
#include "threadDummyImpl.h"
typedef ThreadDummyImpl ThreadImpl;
#elif defined(IPC_NSPR_IMPL)
#include "threadNsprImpl.h"
typedef ThreadNsprImpl ThreadImpl;
#endif
#endif

View File

@ -0,0 +1,74 @@
// Filename: threadNsprImpl.I
// Created by: drose (08Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: ThreadNsprImpl::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE ThreadNsprImpl::
ThreadNsprImpl(Thread *parent_obj) :
_parent_obj(parent_obj)
{
_thread = (PRThread *)NULL;
_joinable = false;
}
////////////////////////////////////////////////////////////////////
// Function: ThreadNsprImpl::prepare_for_exit
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void ThreadNsprImpl::
prepare_for_exit() {
PR_Cleanup();
}
////////////////////////////////////////////////////////////////////
// Function: ThreadNsprImpl::Constructor
// Access: Public, Static
// Description:
////////////////////////////////////////////////////////////////////
INLINE Thread *ThreadNsprImpl::
get_current_thread() {
if (!_got_pt_ptr_index) {
return (Thread *)NULL;
}
return (Thread *)PR_GetThreadPrivate(_pt_ptr_index);
}
////////////////////////////////////////////////////////////////////
// Function: ThreadNsprImpl::is_threading_supported
// Access: Public, Static
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool ThreadNsprImpl::
is_threading_supported() {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: ThreadNsprImpl::sleep
// Access: Public, Static
// Description:
////////////////////////////////////////////////////////////////////
INLINE void ThreadNsprImpl::
sleep(double seconds) {
PR_Sleep((int)(PR_TicksPerSecond() * seconds));
}

View File

@ -0,0 +1,196 @@
// Filename: threadNsprImpl.cxx
// Created by: drose (08Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "threadNsprImpl.h"
#include "selectIpcImpl.h"
#ifdef IPC_NSPR_IMPL
#include "pointerTo.h"
#include "config_express.h"
#include "mutexHolder.h"
PRUintn ThreadNsprImpl::_pt_ptr_index = 0;
bool ThreadNsprImpl::_got_pt_ptr_index = false;
////////////////////////////////////////////////////////////////////
// Function: ThreadNsprImpl::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
ThreadNsprImpl::
~ThreadNsprImpl() {
if (ipc_cat.is_debug()) {
ipc_cat.debug() << "Deleting thread " << _parent_obj->get_name() << "\n";
}
// If the thread object is destructing, it means the last pointer
// has gone away. This can happen in one of three cases:
// (1) start() was never called, and the last user reference has
// gone away. In this case, we should do nothing.
// (2) There are no more user references, and the thread is still
// running but is about to exit root_func(). In this case, no one
// will ever call join().
// (3) The thread terminated a while ago, and the last user
// reference has just gone away. In this case, we should call
// join() if no one else has, to clean up whatever internal
// structures NSPR might keep around for a non-detached thread.
if (_thread == (PRThread *)NULL) {
// Since the _thread pointer is still NULL, we must either be in
// case (1), or case (3) but someone else has already called
// join(). Do nothing.
return;
}
PRThread *current_thread = PR_GetCurrentThread();
if (current_thread == _thread) {
// Since we are currently executing *this* thread, we must be in
// case (2). Unfortunately, we cannot now indicate we need to
// clean up the thread, since NSPR doesn't have an interface to
// make a thread unjoinable after it has been created, and a
// thread can't join itself (can it?).
if (_joinable) {
ipc_cat.warning()
<< "thread " << _parent_obj->get_name() << " was never joined.\n";
}
return;
}
// This is case (3). The pointer went away and the thread has
// already terminated; furthermore, no one has called join() yet.
// We should do it.
join();
}
////////////////////////////////////////////////////////////////////
// Function: ThreadNsprImpl::start
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
bool ThreadNsprImpl::
start(ThreadPriority priority, bool global, bool joinable) {
MutexHolder holder(_mutex);
if (ipc_cat.is_debug()) {
ipc_cat.debug() << "Starting thread " << _parent_obj->get_name() << "\n";
}
nassertr(_thread == (PRThread *)NULL, false);
_joinable = joinable;
if (!_got_pt_ptr_index) {
// Allocate a new index to store the Thread parent pointer as a
// piece of per-thread private data.
PRStatus result = PR_NewThreadPrivateIndex(&_pt_ptr_index, NULL);
if (result == PR_SUCCESS) {
_got_pt_ptr_index = true;
} else {
ipc_cat.error()
<< "Unable to associate Thread pointers with threads.\n";
return false;
}
}
PRThreadPriority nspr_pri;
switch (priority) {
case TP_low:
nspr_pri = PR_PRIORITY_LOW;
break;
case TP_normal:
nspr_pri = PR_PRIORITY_NORMAL;
break;
case TP_high:
nspr_pri = PR_PRIORITY_HIGH;
break;
case TP_urgent:
nspr_pri = PR_PRIORITY_URGENT;
break;
default:
nassertr(false, false);
}
PRThreadScope nspr_scope = (global) ? PR_GLOBAL_THREAD : PR_LOCAL_THREAD;
PRThreadState nspr_state = (_joinable) ? PR_JOINABLE_THREAD : PR_UNJOINABLE_THREAD;
// Increment the parent object's reference count first. The thread
// will eventually decrement it when it terminates.
_parent_obj->ref();
_thread =
PR_CreateThread(PR_USER_THREAD, &root_func, (void *)_parent_obj,
nspr_pri, nspr_scope, nspr_state, 0);
if (_thread == (PRThread *)NULL) {
// Oops, we couldn't start the thread. Be sure to decrement the
// reference count we incremented above, and return false to
// indicate failure.
unref_delete(_parent_obj);
return false;
}
// Thread was successfully started.
return true;
}
////////////////////////////////////////////////////////////////////
// Function: ThreadNsprImpl::join
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void ThreadNsprImpl::
join() {
MutexHolder holder(_mutex);
if (_joinable && _thread != (PRThread *)NULL) {
PR_JoinThread(_thread);
_thread = (PRThread *)NULL;
}
}
////////////////////////////////////////////////////////////////////
// Function: ThreadNsprImpl::root_func
// Access: Private, Static
// Description: The entry point of each thread.
////////////////////////////////////////////////////////////////////
void ThreadNsprImpl::
root_func(void *data) {
Thread *parent_obj = (Thread *)data;
PRStatus result = PR_SetThreadPrivate(_pt_ptr_index, parent_obj);
nassertv(result == PR_SUCCESS);
parent_obj->thread_main();
if (ipc_cat.is_debug()) {
ipc_cat.debug()
<< "Terminating thread " << parent_obj->get_name()
<< ", count = " << parent_obj->get_ref_count() << "\n";
}
// Now drop the parent object reference that we grabbed in start().
// This might delete the parent object, and in turn, delete the
// ThreadNsprImpl object.
unref_delete(parent_obj);
}
#endif // IPC_NSPR_IMPL

View File

@ -0,0 +1,70 @@
// Filename: threadNsprImpl.h
// Created by: drose (08Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef THREADNSPRIMPL_H
#define THREADNSPRIMPL_H
#include "pandabase.h"
#include "selectIpcImpl.h"
#ifdef IPC_NSPR_IMPL
#include "notify.h"
#include "threadPriority.h"
#include "mutex.h"
#include <prthread.h>
#include <prinit.h>
class Thread;
////////////////////////////////////////////////////////////////////
// Class : ThreadNsprImpl
// Description : Uses NSPR to implement a thread.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA ThreadNsprImpl {
public:
INLINE ThreadNsprImpl(Thread *parent_obj);
INLINE ~ThreadNsprImpl();
bool start(ThreadPriority priority, bool global, bool joinable);
void join();
INLINE static void prepare_for_exit();
INLINE static Thread *get_current_thread();
INLINE static bool is_threading_supported();
INLINE static void sleep(double seconds);
private:
static void root_func(void *data);
static void pt_ptr_destructor(void *data);
Mutex _mutex;
Thread *_parent_obj;
PRThread *_thread;
bool _joinable;
static PRUintn _pt_ptr_index;
static bool _got_pt_ptr_index;
};
#include "threadNsprImpl.I"
#endif // IPC_NSPR_IMPL
#endif

View File

@ -1,5 +1,5 @@
// Filename: ipc_library.h
// Created by: frang (10Feb00)
// Filename: threadPriority.h
// Created by: drose (08Aug02)
//
////////////////////////////////////////////////////////////////////
//
@ -16,26 +16,21 @@
//
////////////////////////////////////////////////////////////////////
#ifndef __IPC_LIBRARY_H__
#define __IPC_LIBRARY_H__
#ifndef THREADPRIORITY_H
#define THREADPRIORITY_H
#include <pandabase.h>
#include "pandabase.h"
#include "ipc_traits.h"
class base_library {
public:
typedef ipc_traits traits;
typedef traits::library_class library_class;
static base_library* const Null;
INLINE base_library(std::string& lib) : _lib(traits::make_library(lib)) {}
INLINE ~base_library(void) { delete _lib; }
INLINE void* get_symbol(std::string& sym) { return _lib->get_symbol(sym); }
private:
library_class* _lib;
////////////////////////////////////////////////////////////////////
// An enumerated type used by Thread to specify a suggested relative
// priority for a particular thread.
////////////////////////////////////////////////////////////////////
enum ThreadPriority {
TP_low,
TP_normal,
TP_high,
TP_urgent
};
typedef base_library library;
#endif /* __IPC_LIBRARY_H__ */
#endif

View File

@ -1,33 +0,0 @@
#define LOCAL_LIBS express pandabase
#define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \
dtoolutil:c dtoolbase:c dtool:m
#define USE_PACKAGES nspr ipc
#define BUILD_DIRECTORY $[HAVE_IPC]
#begin lib_target
#define TARGET ipc
#define COMBINED_SOURCES $[TARGET]_composite1.cxx
#define SOURCES \
ipc_atomics.h ipc_condition.h ipc_file.I ipc_file.h \
ipc_library.h ipc_mach_traits.h ipc_mutex.h ipc_nspr_traits.h \
ipc_nt_traits.h ipc_posix_traits.h \
ipc_ps2_traits.h ipc_semaphore.h ipc_solaris_traits.h ipc_thread.h \
ipc_traits.h
#define INCLUDED_SOURCES \
ipc.cxx ipc_traits.cxx
#define INSTALL_HEADERS \
ipc_mutex.h ipc_condition.h ipc_semaphore.h ipc_thread.h \
ipc_traits.h ipc_mach_traits.h ipc_nt_traits.h ipc_posix_traits.h \
ipc_solaris_traits.h ipc_nspr_traits.h ipc_ps2_traits.h \
ipc_atomics.h ipc_library.h ipc_file.h ipc_file.I
#end lib_target
// There needs to be a way to compile this into the ipc library only
// when appropriate. Perhaps as simple as compiling it all the time,
// but protecting the code itself within #ifdefs.
#define EXTRA_DIST ipc_nt_traits.cxx

View File

@ -1,90 +0,0 @@
// Filename: ipc.cxx
// Created by: frang (06Apr00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "ipc_condition.h"
base_condition_variable* const base_condition_variable::Null =
(base_condition_variable*)0L;
#include "ipc_library.h"
base_library* const base_library::Null = (base_library*)0L;
#include "ipc_file.h"
base_file* const base_file::Null = (base_file*)0L;
#include "ipc_mutex.h"
base_mutex* const base_mutex::Null = (base_mutex*)0L;
#include "ipc_semaphore.h"
base_semaphore* const base_semaphore::Null = (base_semaphore*)0L;
#include "ipc_thread.h"
base_thread* const base_thread::Null = (base_thread*)0L;
base_thread::mutex* base_thread::_next_id_mutex = base_thread::mutex::Null;
int base_thread::_next_id = 0;
void* base_thread::thread_wrapper(void* data)
{
base_thread* me = (base_thread *) data;
me->_thread->start_in();
// now invoke the thread functin with the given argument
if (me->_fn_void != NULL)
{
(*me->_fn_void)(me->_thread_arg);
base_thread::exit();
}
if (me->_fn_ret != NULL)
{
void* return_value = (*me->_fn_ret)(me->_thread_arg);
base_thread::exit(return_value);
}
if (me->_detached)
{
me->run(me->_thread_arg);
base_thread::exit();
}
else
{
void* return_value = me->run_undetached(me->_thread_arg);
base_thread::exit(return_value);
}
// we should never get here, but this makes the compilers happy
return (void *) NULL;
}
void base_thread::run(void*) {
}
void* base_thread::run_undetached(void*) {
return (void*)0L;
}

View File

@ -1,4 +0,0 @@
#include "ipc.cxx"
#include "ipc_traits.cxx"

View File

@ -1,52 +0,0 @@
// Filename: ipc_condition.h
// Created by: cary (16Sep98)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef __IPC_CONDITION_H__
#define __IPC_CONDITION_H__
#include <pandabase.h>
#include "ipc_traits.h"
#include "ipc_mutex.h"
class EXPCL_PANDAEXPRESS base_condition_variable {
public:
typedef ipc_traits traits;
typedef traits::condition_class condition_class;
typedef base_mutex mutex;
static base_condition_variable* const Null;
INLINE base_condition_variable(mutex& m) : _mutex(m),
_condition(traits::make_condition(m.get_mutex())) {}
INLINE ~base_condition_variable(void) { delete _condition; }
INLINE void wait(void) { _condition->wait(); }
INLINE int timedwait(const unsigned long secs,
const unsigned long nsecs = 0) {
return _condition->timedwait(secs, nsecs);
}
INLINE void signal(void) { _condition->signal(); }
INLINE void broadcast(void) { _condition->broadcast(); }
INLINE condition_class* get_condition(void) { return _condition; }
private:
mutex& _mutex;
condition_class *_condition;
};
typedef base_condition_variable condition_variable;
#endif /* __IPC_CONDITION_H__ */

View File

@ -1,54 +0,0 @@
// Filename: ipc_file.h
// Created by: jason (05Jun00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef __IPC_FILE_H__
#define __IPC_FILE_H__
#include <pandabase.h>
#include <datagramGenerator.h>
#include <datagramSink.h>
#include "ipc_traits.h"
class base_file {
public:
enum file_mode {FILE_READ, FILE_WRITE, FILE_BOTH, FILE_APPEND};
typedef ipc_traits traits;
typedef traits::file_class file_class;
static base_file* const Null;
INLINE base_file(const string& file = "") : _file(traits::make_file(file)) {}
virtual ~base_file(void) { delete _file; };
INLINE void setFile(const string& file) {_file->setFile(file);}
INLINE bool open(file_mode mode) {return _file->open(mode);}
INLINE void close(void) {_file->close();}
INLINE bool empty(void) { return _file->empty();}
INLINE int readin(string& buffer, int numBytes) {return _file->readin(buffer, numBytes);}
INLINE int writeout(const string& buffer) {return _file->writeout(buffer);}
private:
file_class* _file;
};
typedef base_file file;
typedef file::file_mode file_mode;
#include "ipc_file.I"
#endif /* __IPC_FILE_H__ */

View File

@ -1,297 +0,0 @@
// Filename: ipc_mach_traits.h
// Created by: cary (16Sep98)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef __IPC_MACH_TRAITS_H__
#define __IPC_MACH_TRAITS_H__
#include <pandabase.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/time.h>
#include <mach/cthreads.h>
class EXPCL_PANDAEXPRESS ipc_traits {
public:
class mutex_class;
class condition_class;
class semaphore_class;
class thread_class;
class library_class;
class mutex_class {
private:
struct mutex _mutex;
public:
// interface to mutex
static const mutex_class* Null;
INLINE mutex_class(void) { mutex_init(&_mutex); }
INLINE ~mutex_class(void) { mutex_clear(&_mutex); }
INLINE void lock(void) { mutex_lock(&_mutex); }
INLINE void unlock(void) { mutex_unlock(&_mutex); }
INLINE struct mutex* get_mutex(void) { return &_mutex; }
};
class condition_class {
private:
struct condition _condition;
mutex_class *_mutex;
typedef struct alarmclock_args {
unsigned long secs;
unsigned long nsecs;
bool wakeup;
condition_class* condition;
mutex_class* mutex;
};
INLINE any_t alarmclock(any_t arg) {
alarmclock_args* alarm = (alarmclock_args*)arg;
thread_ipc_traits::sleep(alarm->secs, alarm->nsecs);
alarm->mutex->lock();
alarm->wakeup = TRUE;
alarm->condition->signal();
alarm->mutex->unlock();
return (any_t)TRUE;
}
public:
// interface to condition variables
static const condition_class* Null;
INLINE condition_class(mutex_class* m) : _mutex(m) {
condition_init(&_condition);
}
INLINE ~condition_class(void) { condition_clear(&_condition); }
INLINE void wait(void) {
condition_wait(&_condition, _mutex->get_mutex());
}
INLINE int timedwait(const unsigned long secs,
const unsigned long nsecs) {
alarmclock_args alarm;
thread_ipc_traits::get_time(&alarm.secs, &alarm.nsecs, 0, 0);
if (secs < alarm.secs || (secs == alarm.secs &&
nsecs <= alarm.nsecs))
return ETIMEDOUT;
alarm.secs = secs - alarm.secs;
if (nsecs <= alarm.nsecs) {
alarm.nsecs = 1000000 - alarm.nsecs + nsecs;
--alarm.secs;
} else
alarm.nsecs = nsecs - alarm.nsecs;
alarm.mutex = _mutex;
alarm.condition = this;
alarm.wakeup = FALSE;
cthread_t ct = cthread_fork((cthread_fn_t)alarmclock,
(any_t)&alarm);
cthread_detach(ct);
condition_wait(&_condition, _mutex->get_mutex());
if (alarm.wakeup)
return 0;
// interrupt the alarmclock thread sleep
cthread_abort(ct);
// wait until it has signalled the condition
condition_wait(&_condition, _mutex->get_mutex());
return 1;
}
INLINE void signal(void) { condition_signal(&_condition); }
INLINE void broadcast(void) { condition_signal(&_condition); }
};
class semaphore_class {
private:
mutex_class _mutex;
condition_class _condition;
int _value;
public:
// interface to semaphores
static const semaphore_class* Null;
INLINE semaphore_class(const unsigned int initial) : _mutex(),
_condition(&_mutex), _value(initial) {}
INLINE ~semaphore_class(void) {}
INLINE void wait(void) {
_mutex->lock();
while (_value == 0)
_condition.wait(&_mutex);
--_value;
_mutex->unlock();
}
INLINE int trywait(void) {
_mutex->lock();
if (_value == 0) {
_mutex->unlock();
return 0;
}
--_value;
_mutex->unlock();
return 1;
}
INLINE void post(void) {
_mutex->lock();
if (_value == 0)
_condition.signal();
++_value;
_mutex->unlock();
}
};
class thread_class {
private:
chread_d _thread;
void* _b_ptr; // a handle to hang a pointer back to the high-level
// thread class on. Gross, but I couldn't think of
// a better way to do this reverse lookup.
void* (*_fn)(void*);
INLINE int priority_map(const int pri) {
switch (pri) {
case 0:
return 0;
case 1:
return normal_priority;
case 2:
return high_priority;
default:
return -1;
}
}
static void* thread_wrapper(void*);
public:
// interface to threads
static const thread_class* Null;
INLINE thread_class(void* data) : _b_ptr(data) {}
INLINE ~thread_class(void) {}
INLINE void manual_init(void) {
_thread = cthread_self();
}
INLINE void start_pre(void* (*fn)(void*), const bool, const int) {
_fn = fn;
_thread = cthread_fork(thread_wrapper, (any_t)this);
}
INLINE void start_in(void) {
cthread_set_data(cthread_self(), (any_t)this);
}
INLINE void start_post(const bool det, const int) {
if (det)
cthread_detach(_thread);
}
INLINE void join(void** status) {
*status = cthread_join(_thread);
}
INLINE void set_priority(const int pri) {
kern_return_t rc = cthread_priority(_thread, priority_map(pri),
FALSE);
if (rc != KERN_SUCCESS)
throw thread_fatal(errno);
}
INLINE void* back_ptr(void) { return _b_ptr; }
static INLINE void exit(void* return_value) {
cthread_exit(return_value);
}
static INLINE thread_class* self(void) {
thread_class* me = (thread_class*)cthread_data(cthread_self());
// if (me == thread_class::Null) not one of ours
return me;
}
static INLINE void yield(void) {
cthread_yield();
}
};
class library_class {
public:
static library_class* const Null;
INLINE library_class(str&) {
throw lib_load_invalid();
}
INLINE ~library_class(void) {
throw lib_load_invalid();
}
INLINE void* get_symbol(str&) {
throw lib_load_invalid();
}
};
static INLINE mutex_class *make_mutex(void) {
return new mutex_class;
}
static INLINE condition_class *make_condition(mutex_class* m) {
return new condition_class(m);
}
static INLINE semaphore_class *make_semaphore(const unsigned int initial) {
return new semaphore_class(initial);
}
static INLINE thread_class *make_thread(void* data) {
return new thread_class(data);
}
static INLINE library_class *make_library(str&) {
throw lib_load_invalid();
}
static INLINE void sleep(const unsigned long secs,
const unsigned long nsecs = 0) {
const unsigned MAX_SLEEP_SECONDS=(unsigned)4294966; // (2**32-2)/1000
if (secs <= MAX_SLEEP_SECONDS) {
thread_switch(THREAD_NULL, SWITCH_OPTION_WAIT,
secs * 1000 + nsecs / 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 + nsecs / 1000000);
}
static INLINE void get_time(unsigned long& abs_secs,
unsigned long& abs_nsecs,
const unsigned long rel_secs = 0,
const unsigned long rel_nsecs = 0) {
int rc;
unsigned long tv_sec;
unsigned long tv_nsec;
struct timeval tv;
rc = gettimeofday(&tv, NULL);
if (rc)
throw thread_fatal(rc);
tv_sec = tv.tv_sec;
tv_nsec = tv.tv_usec * 1000;
tv_nsec += rel_nsecs;
tv_sec += rel_secs + tv_nsec / 1000000000;
tv_nsec = tv_nsec % 1000000000;
abs_secs = tv_sec;
abs_nsecs = tv_nsec;
}
static INLINE int set_atomic(int&, int) {
throw set_atomic_invalid();
}
static INLINE int inc_atomic(int&) {
throw inc_atomic_invalid();
}
static INLINE int dec_atomic(int&) {
throw dec_atomic_invalid();
}
// these really should be private, but it's annoying to make config a
// friend
static INLINE __set_normal_priority(int p) {
normal_priority = p;
}
static INLINE __set_highest_priority(int p) {
highest_priority = p;
}
private:
// other data specific to this implementation
static int normal_priority;
static int highest_priority;
};
#endif /* __IPC_MACH_TRAITS_ */

View File

@ -1,53 +0,0 @@
// Filename: ipc_mutex.h
// Created by: cary (16Sep98)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef __IPC_MUTEX_H__
#define __IPC_MUTEX_H__
#include <pandabase.h>
#include "ipc_traits.h"
class EXPCL_PANDAEXPRESS base_mutex {
public:
typedef ipc_traits traits;
typedef traits::mutex_class mutex_class;
static base_mutex* const Null;
INLINE base_mutex(void) : _mutex(traits::make_mutex()) {}
INLINE ~base_mutex(void) { delete _mutex; }
INLINE void lock(void) { _mutex->lock(); }
INLINE void unlock(void) { _mutex->unlock(); }
INLINE mutex_class* get_mutex(void) { return _mutex; }
private:
mutex_class* _mutex;
};
class base_mutex_lock {
public:
typedef base_mutex mutex;
INLINE base_mutex_lock(mutex& m) : _mutex(m) { _mutex.lock(); }
INLINE ~base_mutex_lock(void) { _mutex.unlock(); }
private:
mutex& _mutex;
};
typedef base_mutex mutex;
typedef base_mutex_lock mutex_lock;
#endif /* __IPC_MUTEX_H__ */

View File

@ -1,350 +0,0 @@
// Filename: ipc_nspr_traits.h
// Created by: cary (12Jan00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef __IPC_NSPR_TRAITS_H__
#define __IPC_NSPR_TRAITS_H__
#include <pandabase.h>
#include <nspr.h>
#include "datagram.h"
class EXPCL_PANDAEXPRESS ipc_traits {
public:
class mutex_class;
class condition_class;
class semaphore_class;
class thread_class;
class library_class;
class EXPCL_PANDAEXPRESS mutex_class {
private:
PRLock* _mutex;
public:
// interface to mutex
static mutex_class* const Null;
INLINE mutex_class(void) : _mutex(PR_NewLock()) {
if (_mutex == (PRLock*)0L)
cerr << "COULD NOT GET A MUTEX!" << endl;
}
INLINE ~mutex_class(void) {
PR_DestroyLock(_mutex);
}
INLINE void lock(void) {
PR_Lock(_mutex);
}
INLINE void unlock(void) {
PR_Unlock(_mutex);
}
INLINE PRLock* get_mutex(void) {
return _mutex;
}
};
class EXPCL_PANDAEXPRESS condition_class {
private:
mutex_class* _mutex;
PRCondVar* _condition;
public:
static condition_class* const Null;
INLINE condition_class(mutex_class* m)
: _mutex(m), _condition(PR_NewCondVar(m->get_mutex())) {}
INLINE ~condition_class(void) {
PR_DestroyCondVar(_condition);
}
INLINE void wait(void) {
PR_WaitCondVar(_condition, PR_INTERVAL_NO_TIMEOUT);
}
INLINE int timedwait(const unsigned long secs, const unsigned long nsecs) {
unsigned long s, n;
ipc_traits::get_time(s, n);
PRIntervalTime i = PR_SecondsToInterval(secs - s) +
PR_MicrosecondsToInterval((nsecs - n) / 1000);
PR_WaitCondVar(_condition, i);
return 1;
}
INLINE void signal(void) {
PR_NotifyCondVar(_condition);
}
INLINE void broadcast(void) {
PR_NotifyAllCondVar(_condition);
}
};
class EXPCL_PANDAEXPRESS semaphore_class {
private:
mutex_class _mutex;
condition_class _condition;
int _value;
class EXPCL_PANDAEXPRESS mutex_class_lock {
public:
INLINE mutex_class_lock(mutex_class& m) : _mutex(m) {
_mutex.lock();
}
INLINE ~mutex_class_lock(void) {
_mutex.unlock();
}
private:
mutex_class& _mutex;
};
public:
static semaphore_class* const Null;
INLINE semaphore_class(const unsigned int initial)
: _mutex(), _condition(&_mutex), _value(initial) {}
INLINE ~semaphore_class(void) {}
INLINE void wait(void) {
mutex_class_lock l(_mutex);
while (_value == 0)
_condition.wait();
--_value;
}
INLINE int trywait(void) {
mutex_class_lock l(_mutex);
if (_value == 0)
return 0;
--_value;
return 1;
}
INLINE void post(void) {
mutex_class_lock l(_mutex);
if (_value == 0)
_condition.signal();
++_value;
}
};
class EXPCL_PANDAEXPRESS thread_class {
private:
PRThread* _thread;
void* _b_ptr; // a handle to hang a pointer back to the high-level
// thread class on. Gross, but I couldn't think of a
// better way to do this reverse lookup.
void* (*_fn)(void*);
void* _return_value;
INLINE PRThreadPriority priority_map(const int pri) {
switch (pri) {
case 0:
return PR_PRIORITY_LOW;
case 1:
return PR_PRIORITY_NORMAL;
case 2:
return PR_PRIORITY_HIGH;
}
return PR_PRIORITY_NORMAL;
}
static void thread_wrapper(void*);
public:
static thread_class* const Null;
INLINE thread_class(void* data) : _b_ptr(data) {}
INLINE ~thread_class(void) {}
INLINE void manual_init(void) {
_thread = PR_GetCurrentThread();
}
INLINE void start_pre(void* (*fn)(void*), const bool det, const int pri) {
_fn = fn;
// create the thread, decide it's priority, if it's detached, and if it's
// a kernel thread, etc
_thread = PR_CreateThread(PR_SYSTEM_THREAD, thread_wrapper, this,
priority_map(pri), PR_GLOBAL_BOUND_THREAD,
det?PR_UNJOINABLE_THREAD:PR_JOINABLE_THREAD,
256*1024);
}
INLINE void start_in(void) {
PR_SetThreadPrivate(__get_data_index(), this);
}
INLINE void start_post(const bool, const int) {}
INLINE void join(void** status) {
PR_JoinThread(_thread);
if (status)
*status = _return_value;
}
INLINE void set_priority(const int pri) {
PR_SetThreadPriority(_thread, priority_map(pri));
}
INLINE void* back_ptr(void) { return _b_ptr; }
static INLINE void exit(void* return_value) {
thread_class* me = self();
if (me != thread_class::Null)
me->_return_value = return_value;
// This gives us a seg fault upon exit - NSPR wants us to return from
// the callback function rather than exit()
//exit(0); // assuming that this is really a kernel thread. NSPR offers
// no 'thread exit' facility
}
static INLINE thread_class* self(void) {
return (thread_class*)PR_GetThreadPrivate(__get_data_index());
}
static INLINE void yield(void) {
PR_Sleep(PR_INTERVAL_NO_WAIT);
}
};
class EXPCL_PANDAEXPRESS library_class {
private:
PRLibrary* _lib;
public:
static library_class* const Null;
INLINE library_class(const std::string& lib) {
_lib = PR_LoadLibrary(lib.c_str());
if (_lib == (PRLibrary*)0L) {
nout << "failed to load library '" << lib << "'" << endl;
}
}
INLINE ~library_class(void) {
if (_lib != (PRLibrary*)0L) {
PRStatus stat = PR_UnloadLibrary(_lib);
if (stat == PR_FAILURE)
nout << "failed to unload library" << endl;
}
}
INLINE void* get_symbol(const std::string& sym) {
if (_lib == (PRLibrary*)0L) {
nout << "library not correctly loaded" << endl;
return (void *)0L;
}
return PR_FindSymbol(_lib, sym.c_str());
}
};
class EXPCL_PANDAEXPRESS file_class {
//interface to file IO
public:
INLINE file_class(const std::string& file = "") : _filename(file), _fhandle((PRFileDesc*)NULL){}
INLINE ~file_class() { close(); }
INLINE void setFile(const std::string& file) { _filename = file; close(); }
INLINE bool open(const int mode) {
close();
switch(mode){
case 0: _fhandle = PR_Open(_filename.c_str(), PR_RDONLY, 00666); break;
case 1: _fhandle = PR_Open(_filename.c_str(),
PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 00666); break;
case 2: _fhandle = PR_Open(_filename.c_str(),
PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 00666); break;
case 3: _fhandle = PR_Open(_filename.c_str(), PR_APPEND | PR_CREATE_FILE, 00666); break;
default: _fhandle = PR_Open(_filename.c_str(), PR_RDONLY, 00666); break;
}
return (_fhandle != (PRFileDesc *)NULL);
}
INLINE void close(void) {
if (_fhandle != (PRFileDesc *)NULL) { PR_Close(_fhandle); _fhandle = (PRFileDesc *)NULL; }
}
INLINE bool empty(void){ return (PR_Available(_fhandle) <= 0); }
INLINE int readin(string &block, int numBytes) {
//Don't try and read less than nothing
if (_fhandle == (PRFileDesc *)NULL)
return 0;
nassertr(numBytes >= 0, 0);
char* temp = new char[numBytes];
int numRead = PR_Read(_fhandle, temp, numBytes);
if(numRead < 0) {
cerr << "PR_Read() in libnspr failed!\n";
delete temp;
return 0;
}
block.assign(temp, numRead);
delete temp;
return numRead;
}
INLINE int writeout(const string &block) {
nassertr(block.size() > 0, 0); //Make sure there is something to write out
nassertr(block.data() != NULL, 0);
if (_fhandle == (PRFileDesc *)NULL)
return 0;
return PR_Write(_fhandle, (void*)block.data(), block.size());
}
private:
string _filename;
PRFileDesc* _fhandle;
};
static INLINE mutex_class* make_mutex(void) {
return new mutex_class;
}
static INLINE condition_class* make_condition(mutex_class* m) {
return new condition_class(m);
}
static INLINE semaphore_class* make_semaphore(const unsigned int initial) {
return new semaphore_class(initial);
}
static INLINE thread_class* make_thread(void* data) {
return new thread_class(data);
}
static INLINE library_class *make_library(const std::string& lib) {
return new library_class(lib);
}
static INLINE file_class *make_file(const std::string& file) {
return new file_class(file);
}
static INLINE void sleep(const unsigned long secs,
const unsigned long nsecs = 0) {
PRIntervalTime i = PR_SecondsToInterval(secs) +
PR_MicrosecondsToInterval(nsecs / 1000);
PR_Sleep(i);
}
static INLINE void get_time(unsigned long& abs_secs,
unsigned long& abs_nsecs,
const unsigned long rel_secs = 0,
const unsigned long rel_nsecs = 0) {
PRTime t = PR_Now();
PRTime t_offset;
PRTime usec_convert;
PRTime rel_time;
PRTime w, x, y;
PRTime s, n;
// really this step should only ever be done once
LL_UI2L(usec_convert, PR_USEC_PER_SEC);
LL_UI2L(w, rel_secs);
LL_UI2L(x, (rel_nsecs / 1000));
LL_MUL(y, usec_convert, w);
LL_ADD(rel_time, x, y); // the PRTime representing the rel componant
LL_ADD(t_offset, t, rel_time);
LL_DIV(s, t_offset, usec_convert);
LL_MOD(n, t_offset, usec_convert);
LL_L2UI(abs_secs, s);
LL_L2UI(abs_nsecs, n);
abs_nsecs *= 1000;
}
static INLINE int set_atomic(int& var, int val) {
return PR_AtomicSet(&var, val);
}
static INLINE int inc_atomic(int& var) {
return PR_AtomicIncrement(&var);
}
static INLINE int dec_atomic(int& var) {
return PR_AtomicDecrement(&var);
}
// this really should be private, but it's annoying to make config a
// friend
static INLINE void __set_data_index(PRUintn d) {
_data_index = d;
}
static INLINE PRUintn __get_data_index(void) {
return _data_index;
}
private:
// other data specific to this implementation
static PRUintn _data_index;
};
#endif /* __IPC_NSPR_TRAITS_H__ */

View File

@ -1,569 +0,0 @@
// Filename: ipc_nt_traits.h
// Created by: cary (16Sep98)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef __IPC_NT_TRAITS_H__
#define __IPC_NT_TRAITS_H__
#include <pandabase.h>
#include <stdlib.h>
#include <errno.h>
#define WINDOWS_LEAN_AND_MEAN
#include <windows.h>
#undef WINDOWS_LEAN_AND_MEAN
#include <process.h>
#ifdef WIN32_VC
const unsigned long SEMAPHORE_MAX = 0x7fffffff;
#endif
// much of the *next and *prev linked list stuff in here should probably be
// done with STL containers. Examine this when time permits.
class EXPCL_PANDAEXPRESS ipc_traits {
public:
class mutex_class;
class condition_class;
class semaphore_class;
class thread_class;
class library_class;
class file_class;
class mutex_class {
private:
CRITICAL_SECTION _mutex;
public:
// interface to mutex
static const mutex_class* Null;
INLINE mutex_class(void) { InitializeCriticalSection(&_mutex); }
INLINE ~mutex_class(void) { DeleteCriticalSection(&_mutex); }
INLINE void lock(void) { EnterCriticalSection(&_mutex); }
INLINE void unlock(void) { LeaveCriticalSection(&_mutex); }
};
class thread_class {
private:
HANDLE _handle;
DWORD _id;
void* _return_value;
HANDLE _condition;
thread* _tnext;
thread* _tprev;
BOOL _waiting;
void* _b_ptr; // a handle to hang a pointer back to the high-level
// thread class on. Gross, but I couldn't think of
// a better way to do this reverse lookup.
void* (*_fn)(void*);
INLINE int priority_map(const int pri) {
switch (pri) {
case 0:
return THREAD_PRIORITY_LOWEST;
case 1:
return THREAD_PRIORITY_NORMAL;
case 2:
return THREAD_PRIORITY_HIGHEST;
}
throw thread_invalid();
// never gets here, but keeps the compiler happy
return 0;
}
#ifndef __BCPLUSPLUS__
static unsigned _stdcall thread_wrapper(void*);
#else
static void _USERENTRY thread_wrapper(void*);
#endif
public:
// interface to threads
static const thread_class* Null;
INLINE thread_class(void* data) : _b_ptr(data),
_tnext(thread_class::Null), _tprev(thread_class::Null),
_waiting(FALSE), _handle(NULL) {
_condition = CreateSemaphore(NULL, 0, SEMAPHORE_MAX, NULL);
if (_condition == NULL)
throw thread_fatal(GetLastError());
}
INLINE ~thread_class(void) {
if (!CloseHandle(_handle))
throw thread_fatal(GetLastError());
if (!CloseHandle(_condition))
throw thread_fatal(GetLastError());
}
INLINE void manual_init(void) {
if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
GetCurrentProcess(), &_handle, 0, FALSE,
DUPLICATE_SAME_ACCESS))
throw thread_fatal(GetLastError());
_id = GetCurrentThreadId();
if (!SetThreadPriority(_handle, priority_map(PRIORITY_NORMAL)))
throw thread_fatal(GetLastError());
}
INLINE void start_pre(void* (*fn)(void*), const bool, const int) {
_fn = fn;
#ifndef __BCPLUSPLUS__
// MSVC++ or compatable
unsigned int t;
_handle = (HANDLE)_beginthreadex(NULL, 0, thread_wrapper,
(LPVOID)this, CREATE_SUSPENDED,
&t);
_id = t;
if (_handle == NULL)
throw thread_fatal(GetLastError());
#else
// Borland C++
_handle = (HANDLE)_beginthreadNT(thread_wrapper, 0, (void*)this,
NULL, CREATE_SUSPENDED, &_id);
if (_handle == INVALID_HANDLE_VALUE)
throw thread_fatal(errno);
#endif
}
INLINE void start_in(void) {
if (!TlsSetValue(self_tls_index, (LPVOID)this))
throw thread_fatal(GetLastError());
}
INLINE void start_post(const bool, const int pri) {
if (!SetThreadPriority(_handle, pri))
throw thread_fatal(GetLastError());
if (ResumeThread(_handle) == 0xffffffff)
throw thread_fatal(GetLastError());
}
INLINE void join(void** status) {
if (WaitForSingleObject(_handle, INFINITE) != WAIT_OBJECT_0)
throw thread_fatal(GetLastError());
if (status)
*status = _return_value;
}
INLINE void set_priority(const int pri) {
if (!SetThreadPriority(_handle, priority_map(pri)))
throw thread_fatal(GetLastError());
}
INLINE void* back_ptr(void) { return _b_ptr; }
static INLINE void exit(void* return_value) {
thread_class* me = self();
if (me != thread_class::Null)
me->_return_val = return_value;
#ifndef __BCPLUSPLUS__
_endthreadex(0);
#else
_endthread();
#endif
}
static INLINE thread_class* self(void) {
LPVOID me = TlsGetValue(self_tls_index);
if (me == NULL)
return thread_class::Null;
return (thread_class*)me;
}
static INLINE void yield(void) {
Sleep(0);
}
};
// Condition variables are rather annoying 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 xv, 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 it's 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 reather than that it timed out.
//
// It is possible that the thread calling wait or timedwait is not one
// of our threads. 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_thread_dummy
// provides such a data structure and _internal_thread_helper is a helper
// class to deal with this special case for wait() and timedwait(). Once
// created, the _internal_thread_dummy is cached for use by the next
// wait() or timedwait() call from a thread that is not one of ours.
// This is probably worth doing because creating a Semaphore is quite
// heavy weight.
class condition_class {
private:
CRITICAL_SECTION _condition;
thread_class* waiting_head;
thread_class* waiting_tail;
mutex_class* _mutex;
class _internal_thread_helper;
class _internal_thread_dummy : public thread_class {
public:
INLINE _internal_thread_dummy(void) :
next((_internal_thread_dummy*)0L) {}
INLINE ~_internal_thread_dummy(void) {}
friend class _internal_thread_helper;
private:
_internal_thread_dummy* next;
};
class _internal_thread_helper {
public:
INLINE _internal_thread_helper(void) :
d((_internal_thread_dummy*)0L),
t(thread_class::self()) {
if (cachelock == mutex_class::Null)
cachelock = new mutex_class;
if (t == thread_class::Null) {
cachelock->lock();
if (cache) {
d = cache;
cache = cache->next;
} else
d = new _internal_tread_dummy;
t = d;
cachelock->unlock();
}
}
INLINE ~_internal_thread_helper(void) {
if (d != (_internal_thread_dummy*)0L) {
cachelock->lock();
d->next = cache;
cache = d;
cachelock->unlock();
}
}
INLINE operator thread_class*(void) { return t; }
INLINE thread_class* operator->(void) { return t; }
static _internal_thread_dummy* cache;
static mutex_class* cachelock;
private:
_internal_thread_dummy* d;
thread_class* t;
};
public:
// interface to condition variables
static const condition_class* Null;
INLINE condition_class(mutex_class*) : _mutex(m) {
InitializeCriticalSection(&_condition);
waiting_head = waiting_tail = thread_class::Null;
}
INLINE ~condition_class(void) {
DeleteCriticalSection(&_condition);
if (waiting_head != thread_class::Null)
DEBUG() << "thread_ipc_traits<\"nt\">::condition_class::~condition_class : list of waiting threads is not empty" << nend;
}
INLINE void wait(void) {
_internal_thread_helper me;
EnterCriticalSection(&_condition);
me->cond_next = thread_class::Null;
me->cond_prev = waiting_tail;
if (waiting_head == thread_class::Null)
waiting_head = me;
else
waiting_tail->cond_next = me;
waiting_tail = me;
me->cond_waiting = TRUE;
LeaveCriticalSection(&_condition);
_mutex->unlock();
DWORD result = WaitForSingleObject(me->cond_semaphore, INFINITE);
_mutex->lock();
if (result != WAIT_OBJECT_0)
throw condition_fatal(GetLastError());
}
INLINE int timedwait(const unsigned long secs,
const unsigned long nsecs) {
_internal_thread_helper me;
EnterCriticalSection(&_condition);
me->cond_next = thread_class::Null;
me->cond_pref = waiting_tail;
if (waiting_tail == thread_class::Null)
waiting_head = me;
else
waiting_tail->cond_next = me;
waiting_tail = me;
me->cond_waiting = TRUE;
LeaveCriticalSection(&_condition);
_mutex->unlock();
unsigned long now_sec, now_nsec;
thread_ipc_traits::get_time_now(now_sec, now_nsec);
DWORD timeout = (secs - now_sec) * 1000 +
(nsecs - now_nsecs) / 1000000;
if ((secs <= new_sec) && ((secs < now_sec) ||
(nsecs < now_nsecs)))
timeout = 0;
DWORD result = WaitForSingleObject(me->cond_semaphore, timeout);
if (result == WAIT_TIMEOUT) {
EnterCriticalSection(&_condition);
if (me->cond_waiting) {
if (me->cond_prev != thread_class::Null)
me->cond_prev->cond_next = me->cond_next;
else
waiting_head = me->cond_next;
if (me->cond_next != thread_class::Null)
me->cond_next->cond_prev = me->cond_prev;
else
waiting_tail = me->cond_prev;
me->cond_waiting = FALSE;
LeaveCriticalSection(&_condition);
_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(&_condition);
result = WaitForSingleObject(me->cond_semaphore, INFINITE);
}
if (result != WAIT_OBJECT_0)
throw condition_fatal(GetLastError());
_mutex->lock();
return 1;
}
INLINE void signal(void) {
EnterCriticalSection(&_condition);
if (waiting_head != thread_class::Null) {
thread_class* t = waiting_head;
waiting_head = t->cond_next;
if (waiting_head == thread_class::Null)
waiting_tail = thread_class::Null;
else
waiting_head->cond_prev = thread_class::Null;
t->cond_waiting = FALSE;
if (!ReleaseSemaphore(t->cond_semaphore, 1, NULL)) {
int rc = GetLastError();
LeaveCriticalSection(&_condition);
throw condition_fatal(rc);
}
}
LeaveCriticalSection(&_condition);
}
INLINE void broadcast(void) {
EnterCriticalSection(&_condition);
while (waiting_head != thread_class::Null) {
thread_class* t = waiting_head;
waiting_head = t->cond_next;
if (waiting_head == thread_class::Null)
waiting_tail = thread_class::Null;
else
waiting_head->cond_prev = thread_class::Null;
t->cond_waiting = FALSE;
if (!ReleaseSemaphore(t->cond_semaphore, 1, NULL)) {
int rc = GetLastError();
LeaveCriticalSection(&_condition);
throw condition_fatal(rc);
}
}
LeaveCriticalSection(&_condition);
}
};
class semaphore_class {
private:
HANDLE _semaphore;
#ifndef WIN32_VC
const unsigned long SEMAPHORE_MAX = 0x7fffffff;
#endif
public:
// interface to semaphores
static const semaphore_class* Null;
INLINE semaphore_class(const unsigned int initial) :
_semaphore(CreateSemaphore(NULL, initial, SEMAPHORE_MAX, NULL)) {
if (_semaphore == NULL) {
DEBUG() << "thread_ipc_traits<\"nt\">::semaphore_class::semaphore_class : CreateSemaphore error "
<< GetLastError() << nend;
throw semaphore_fatal(GetLastError());
}
}
INLINE ~semaphore_class(void) {
if (!CloseHandle(_semaphore)) {
DEBUG() << "thread_ipc_traits<\"nt\">::semaphore_class::~semaphore_class : CloseHandle error "
<< GetLastError() << nend;
throw semaphore_fatal(GetLastError());
}
}
INLINE void wait(void) {
if (WaitForSingleObject(_semaphore, INFINITE) != WAIT_OBJECT_0)
throw semaphore_fatal(GetLastError());
}
INLINE int trywait(void) {
switch (WaitForSingleObject(_semaphore, 0)) {
case WAIT_OBJECT_0: return 1;
case WAIT_TIMEOUT: return 0;
}
throw semaphore_fatal(GetLastError());
return 0; // never really gets here, but the compilers like it
}
INLINE void post(void) {
if (!ReleaseSemaphore(_semaphore, 1, NULL))
throw semaphore_fatal(GetLastError());
}
};
class library_class {
public:
// interface to dynamically loaded libraries
static library_class* const Null;
INLINE library_class(std::string&) {
throw lib_load_invalid();
}
INLINE ~library_class(void) {
throw lib_load_invalid();
}
INLINE void* get_symbol(std::string&) {
throw lib_load_invalid();
}
};
// BROKEN!! NOT FINISHED
class file_class {
//interface to file IO
public:
INLINE file_class(std::string& file) : _filename(file), _fhandle(NULL){};
INLINE file_class() : _filename(NULL), _fhandle(NULL) {};
INLINE ~file_class() { close(); }
INLINE void setFile(std::string& file) { _filename = file; close(); }
INLINE bool open(const int mode) {
close();
if (_filename.data() != NULL) {
switch(mode){
case 0: _fhandle = fopen(_filename.data(), "rb"); break;
case 1: _fhandle = fopen(_filename.data(), "wb"); break;
case 2: _fhandle = fopen(_filename.data(), "rwb"); break;
default: _fhandle = fopen(_filename.data(), "rb"); break;
}
if (_fhandle != NULL) return true;
}
return false;
}
INLINE void close(void) {
if (_fhandle != NULL) { fclose(_fhandle); _fhandle = NULL; }
}
/*
INLINE bool readin(MemBuf& buffer, int numBytes) {
BYTE* block = new BYTE[numBytes];
if (_fhandle != NULL){
fread(block, sizeof(BYTE), numBytes, _fhandle);
if (!ferror(_fhandle)){ buffer.addBack(block); delete [] block; return true; }
}
delete [] block;
return false;
}
INLINE bool writeout(MemBuf& buffer, int numBytes) {
BYTE* block = buffer.getBlock(0, numBytes);
if (_fhandle != NULL) {
fwrite(block, sizeof(BYTE), numBytes, _fhandle);
if (!ferror(_fhandle)) { delete [] block; return true; }
}
delete [] block;
return false;
}
INLINE bool readin(BYTE* block, int numBytes) {
if (_fhandle != NULL){
fread(block, sizeof(BYTE), numBytes, _fhandle);
if (!ferror(_fhandle)){ return true; }
}
return false;
}
INLINE bool writeout(BYTE* block, int numBytes) {
if (_fhandle != NULL) {
fwrite(block, sizeof(BYTE), numBytes, _fhandle);
if (!ferror(_fhandle)) { return true; }
}
return false;
}
*/
private:
string _filename;
FILE* fhandle;
};
static INLINE mutex_class *make_mutex(void) {
return new mutex_class;
}
static INLINE condition_class *make_condition(mutex_class* m) {
return new condition_class(m);
}
static INLINE semaphore_class *make_semaphore(const unsigned int initial) {
return new semaphore_class(initial);
}
static INLINE thread_class *make_thread(void* data) {
return new thread_class(data);
}
static INLINE library_class *make_thread(std::string&) {
throw lib_load_invalid();
}
static INLINE file_class *make_file(std::string& file) {
return new file_class(file);
}
static INLINE void sleep(const unsigned long secs,
const unsigned long nsecs = 0) {
const DWORD MAX_SLEEP_SECONDS = (DWORD)4294966; // (2**32-2)/1000
if (secs <= MAX_SLEEP_SECONDS) {
Sleep(secs * 1000 + nsecs / 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 + nsecs / 1000000);
}
static INLINE void get_time(unsigned long& abs_secs,
unsigned long& abs_nsecs,
const unsigned long rel_secs = 0,
const unsigned long rel_nsecs = 0) {
get_time_now(&abs_secs, &abs_nsecs);
abs_nsecs += rel_nsecs;
abs_secs += rel_secs + abs_nsecs / 1000000000;
abs_nsecs = abs_nsecs % 1000000000;
}
static INLINE int set_atomic(int&, int) {
throw set_atomic_invalid();
}
static INLINE int inc_atomic(int&, int) {
throw inc_atomic_invalid();
}
static INLINE int dec_atomic(int&, int) {
throw dec_atomic_invalid();
}
// this really should be private, but it is annoying to make config a
// friend
static INLINE void __set_self_tls_index(DWORD i) {
self_tls_index = i;
}
private:
// other data specific to this implementation
static DWORD self_tls_index;
// and a special, bonus, NT implementation function
static const int days_in_preceding_months[12];
static const int days_in_preceding_months_leap[12];
static INLINE void get_time_now(unsigned long& abs_sec,
unsigned long& abs_nsec) {
SYSTEMTIME st;
GetSystemTime(&st);
abs_nsec = st.wMilliseconds * 1000000;
// this formula should work until the 1st of March 2100. If this code
// is still in use by then, I pitty us all.
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));
}
};
#endif /* __IPC_NT_TRAITS_H__ */

View File

@ -1,457 +0,0 @@
// Filename: ipc_posix_traits.h
// Created by: cary (16Sep98)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef __IPC_POSIX_TRAITS_H__
#define __IPC_POSIX_TRAITS_H__
#include <pandabase.h>
#if defined(__alpha__) && defined(__osf1__) || defined(__hpux__)
// stop unnecessary definitions of TRY, etc on OSF
#ifndef EXC_HANDLING
#define EXC_HANDLING
#endif /* EXC_HANDLING */
#endif /* __alpha__, __hpux__ */
// hack alert!
#ifdef __GNUC__
#define _MIT_POSIX_THREADS 1
#define PthreadDraftVersion 7
#define NoNanoSleep
#include <unistd.h>
/*
extern "C" {
void usleep(unsigned long);
}
*/
#endif /* __GNUC__ */
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include <pthread.h>
#if (defined(__GLIBC__) && __GLIBC__ >= 2)
// typedef of struct timeval and gettimeofday();
#include <sys/time.h>
#include <unistd.h>
#endif /* __GLIBC__ */
// #if defined(__linux__) && defined(_MIT_POSIX_THREADS)
// #include <sys/timers.h>
// #endif /* __linux__ & _MIT_POSIX_THREADS */
#if defined(__sgi)
#define PthreadSupportThreadPriority
// this next is just a guess
#define PthreadDraftVersion 10
#include <sched.h>
#endif
#define THROW_FATAL(x, t) throw t##_fatal(x)
#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, t) { if ((x) == -1) THROW_FATAL(errno, t); }
#else
#define THROW_ERRORS(x, t) { if ((x) != 0) THROW_FATAL(errno, t); }
#endif /* __VMS */
#else
#define ERRNO(x) (x)
#define THROW_ERRORS(x, t) { int rc = (x); \
if (rc != 0) THROW_FATAL(rc, t); }
#endif /* PthreadDraftVersion 6 */
#define THROW_ERRORS_G(x) THROW_ERRORS(x, ipc)
#define THROW_ERRORS_M(x) THROW_ERRORS(x, mutex)
#define THROW_ERRORS_C(x) THROW_ERRORS(x, condition)
#define THROW_ERRORS_S(x) THROW_ERRORS(x, semaphore)
#define THROW_ERRORS_T(x) THROW_ERRORS(x, thread)
class EXPCL_PANDAEXPRESS ipc_traits {
public:
class mutex_class;
class condition_class;
class semaphore_class;
class thread_class;
class library_class;
class mutex_class {
private:
pthread_mutex_t _mutex;
public:
// interface to mutex
static mutex_class* const Null;
INLINE mutex_class(void) {
#if (PthreadDraftVersion == 4)
THROW_ERRORS_M(pthread_mutex_init(&_mutex, pthread_mutexattr_default));
#else
THROW_ERRORS_M(pthread_mutex_init(&_mutex, 0));
#endif
}
INLINE ~mutex_class(void) {
THROW_ERRORS_M(pthread_mutex_destroy(&_mutex));
}
INLINE void lock(void) {
THROW_ERRORS_M(pthread_mutex_lock(&_mutex));
}
INLINE void unlock(void) {
THROW_ERRORS_M(pthread_mutex_unlock(&_mutex));
}
INLINE pthread_mutex_t* get_mutex(void) { return &_mutex; }
};
class condition_class {
private:
pthread_cond_t _condition;
mutex_class* _mutex;
public:
// interface to condition variables
static condition_class* const Null;
INLINE condition_class(mutex_class* m) : _mutex(m) {
#if (PthreadDraftVersion == 4)
THROW_ERRORS_C(pthread_cond_init(&_condition, pthread_condattr_default));
#else
THROW_ERRORS_C(pthread_cond_init(&_condition, 0));
#endif
}
INLINE ~condition_class(void) {
THROW_ERRORS_C(pthread_cond_destroy(&_condition));
}
INLINE void wait(void) {
THROW_ERRORS_C(pthread_cond_wait(&_condition,
_mutex->get_mutex()));
}
INLINE int timedwait(const unsigned long secs,
const unsigned long nsecs) {
timespec rqts = { (long)secs, (long)nsecs };
int rc = ERRNO(pthread_cond_timedwait(&_condition,
_mutex->get_mutex(),
&rqts));
if (rc == 0)
return 1;
#if (PthreadsDraftVersion <= 6)
if (rc == EAGAIN)
return 0;
#endif
if (rc == ETIMEDOUT)
return 0;
throw condition_fatal(rc);
}
INLINE void signal(void) {
THROW_ERRORS_C(pthread_cond_signal(&_condition));
}
INLINE void broadcast(void) {
THROW_ERRORS_C(pthread_cond_broadcast(&_condition));
}
};
class semaphore_class {
private:
mutex_class _mutex;
condition_class _condition;
int _value;
class mutex_class_lock {
public:
INLINE mutex_class_lock(mutex_class& m) : _mutex(m) {
_mutex.lock();
}
INLINE ~mutex_class_lock(void) { _mutex.unlock(); }
private:
mutex_class& _mutex;
};
public:
// interface to semaphores
static semaphore_class* const Null;
INLINE semaphore_class(const unsigned int initial) : _mutex(),
_condition(&_mutex), _value(initial) {}
INLINE ~semaphore_class(void) {}
INLINE void wait(void) {
mutex_class_lock l(_mutex);
while (_value == 0)
_condition.wait(&_mutex);
--_value;
}
INLINE int trywait(void) {
mutex_class_lock l(_mutex);
if (_value == 0) {
return 0;
}
--_value;
return 1;
}
INLINE void post(void) {
mutex_class_lock l(_mutex);
if (_value == 0)
_condition.signal();
++_value;
}
};
class thread_class {
private:
pthread_t _thread;
void* _b_ptr; // a handle to hang a pointer back to the high-level
// thread class on. Gross, but I couldn't think of
// a better way to do this reverse lookup.
void* (*_fn)(void*);
INLINE int priority_map(const int pri) {
#ifdef PthreadSupportThreadPriority
switch (pri) {
case 0:
return lowest_priority;
case 1:
return normal_priority;
case 2:
return highest_priority;
}
#endif /* PthreadSupportThreadPriority */
throw thread_invalid();
}
static void* thread_wrapper(void*);
public:
// interface to threads
static thread_class* const Null;
INLINE thread_class(void* data) : _b_ptr(data) {}
INLINE ~thread_class(void) {}
INLINE void manual_init(void) {
_thread = pthread_self();
#ifdef PthreadSupportPriority
#if (PthreadDraftVersion == 4)
THROW_ERRORS_T(pthread_setprio(_thread,
priority_map(PRIORITY_NORMAL)));
#elif (PthreadDraftVersion == 6)
pthread_attr_t attr;
pthread_attr_init(&attr);
THROW_ERRORS_T(pthread_attr_setprio(&attr,
priority_map(PRIORITY_NORMAL)));
THROW_ERRORS_T(pthread_setschedattr(_thread, attr));
#else
struct sched_param sparam;
sparam.sched_priority = priority_map(PRIORITY_NORMAL);
THROW_ERRORS_T(pthread_setschedparam(_thread, SCHED_OTHER,
&param));
#endif /* PthreadDraftVersion */
#endif /* PthreadSupportPriority */
}
INLINE void start_pre(void* (*fn)(void*), const bool,
const int pri) {
_fn = fn;
pthread_attr_t attr;
#if (PthreadDraftVersion == 4)
pthread_attr_create(&attr);
#else
pthread_attr_init(&attr);
#endif
#if (PthreadDraftVersion == 8)
pthread_attr_setdetachedstate(&attr, PTHREAD_CREATE_UNDETACHED);
#endif
#ifdef PthreadSupportThreadPriority
#if (PthreadDraftVersion <= 6)
THROW_ERRORS_T(pthread_attr_setprio(&attr, priority_map(pri)));
#else
struct sched_param sparam;
sparam.sched_priority = priority_map(pri);
THROW_ERRORS_T(pthread_attr_setschedparam(&attr, &sparam));
#endif
#endif /* PthreadSupportThreadPriority */
#if defined(__osf1__) && defined(__alpha__) || defined(__VMS)
// we're going to require a larger stack size then the default
// (21120) on OSF/1
THROW_ERRORS_T(pthread_attr_setstacksize(&attr, 32768));
#endif
#if (PthreadDraftVersion == 4)
THROW_ERRORS_T(pthread_create(&_thread, attr, thread_wrapper,
(void*)this));
pthread_attr_delete(&attr);
#else
THROW_ERRORS_T(pthread_create(&_thread, &attr, thread_wrapper,
(void*)this));
pthread_attr_destroy(&attr);
#endif
}
INLINE void start_in(void) {
THROW_ERRORS_T(pthread_setspecific(self_key, this));
}
INLINE void start_post(const bool det, const int) {
if (det) {
#if (PthreadDraftVersion <= 6)
THROW_ERRORS_T(pthread_detach(&_thread));
#else
THROW_ERRORS_T(pthread_detach(_thread));
#endif
}
}
INLINE void join(void** status) {
THROW_ERRORS_T(pthread_join(_thread, status));
#if (PthreadDraftVersion == 4)
// With draft 4 pthreads implementations (HPUS 10.x and Digital
// Unix 3.2), you have to detach the thread after join. If not,
// the storage for the thread will not be reclaimed.
THROW_ERRORS_T(pthread_detach(&_thread));
#endif
}
INLINE void set_priority(const int pri) {
#ifdef PthreadSupportThreadPriority
#if (PthreadDraftVersion == 4)
THROW_ERRORS_T(pthread_setprio(_thread, priority_map(pri)));
#elif (PthreadDraftVersion == 6)
pthread_attr_t attr;
pthread_attr_init(&attr);
THROW_ERRORS_T(pthread_attr_setprio(&attr, priority_map(pri)));
THROW_ERRORS_T(pthread_setschedattr(_thread, attr));
#else
struct sched_param sparam;
sparam.sched_priority = priority_map(pri);
THROW_ERRORS_T(pthread_setschedparam(_thread, SCHED_OTHER,
&sparam));
#endif
#endif /* PthreadSupportThreadPriority */
}
INLINE void* back_ptr(void) { return _b_ptr; }
static INLINE void exit(void* return_value) {
pthread_exit(return_value);
}
static INLINE thread_class* self(void) {
thread_class* me(thread_class::Null);
#if (PthreadDraftVersion <= 6)
THROW_ERRORS_T(pthread_getspecific(self_key, (void**)&me));
#else
me = (thread_class*)pthread_getspecific(self_key);
#endif
return me;
}
static INLINE void yield(void) {
#if (PthreadDraftVersion == 6)
pthread_yield(NULL);
#elif (PthreadDraftVersion < 9)
pthread_yield();
#else
THROW_ERRORS_T(sched_yield());
#endif
}
};
class library_class {
public:
static library_class* const Null;
INLINE library_class(ConfigString&) {
throw lib_load_invalid();
}
INLINE ~library_class(void) {
throw lib_load_invalid();
}
INLINE void* get_symbol(ConfigString&) {
throw lib_load_invalid();
}
};
static INLINE mutex_class *make_mutex(void) {
return new mutex_class;
}
static INLINE condition_class *make_condition(mutex_class* m) {
return new condition_class(m);
}
static INLINE semaphore_class *make_semaphore(const unsigned int initial) {
return new semaphore_class(initial);
}
static INLINE thread_class *make_thread(void* data) {
return new thread_class(data);
}
static INLINE library_class *make_library(ConfigString&) {
throw lib_load_invalid();
}
static INLINE void sleep(const unsigned long secs,
const unsigned long nsecs = 0) {
timespec rqts = { (long)secs, (long)nsecs};
#ifndef NoNanoSleep
if (nanosleep(&rqts, (timespec*)NULL) != 0) {
throw ipc_fatal(errno);
}
#else
#if defined(__osf1__) && defined(__alpha__) || defined(__hpux__) && (__OSVERSION__ == 10) || defined(__VMS) || defined(__SINIX__)
if (pthread_delay_np(&rqts) != 0) {
throw ipc_fatal(errno);
}
#elif defined(__linux__) || defined(__aix__)
// this seems terribly inaccurate, and should be re-examined
if (secs > 2000)
sleep(secs);
else
usleep(secs * 1000000 + (nsecs / 1000));
#else
throw ipc_invalid();
#endif
#endif /* NoNanoSleep */
}
static INLINE void get_time(unsigned long& abs_secs,
unsigned long& abs_nsecs,
const unsigned long rel_secs = 0,
const unsigned long rel_nsecs = 0) {
timespec abs;
#if defined(__osf1__) && defined(__alpha__) || defined(__hpux__) && (__OSVERSION__ == 10) || defined(__VMS) || defined(__SINIX__)
timespec rel;
rel.tv_sec = rel_secs;
rel.tv_nsec = rel_nsecs;
THROW_ERRORS_G(pthread_get_expiration_np(&rel, &abs));
#else
#if defined(__linux__) || defined(__aix__)
struct timeval tv;
gettimeofday(&tv, NULL);
abs.tv_sec = tv.tv_sec;
abs.tv_nsec = tv.tv_usec * 1000;
#else
clock_gettime(CLOCK_REALTIME, &abs);
#endif /* __linux__, __aix__, ... */
abs.tv_nsec += rel_nsecs;
abs.tv_sec += rel_secs + abs.tv_nsec / 1000000000;
abs.tv_nsec = abs.tv_nsec & 1000000000;
#endif /* __osf1__, __alpha__, ... */
abs_secs = abs.tv_sec;
abs_nsecs = abs.tv_nsec;
}
static INLINE int set_atomic(int&, int) {
throw set_atomic_invalid();
}
static INLINE int inc_atomic(int&) {
throw inc_atomic_invalid();
}
static INLINE int dec_atomic(int&) {
throw dec_atomic_invalid();
}
// These should be private, but is annoying to make config a
// friend
static INLINE void __set_self_key(pthread_key_t k) {
self_key = k;
}
static INLINE void __set_lowest_priority(int p) {
lowest_priority = p;
}
static INLINE void __set_normal_priority(int p) {
normal_priority = p;
}
static INLINE void __set_highest_priority(int p) {
highest_priority = p;
}
private:
// other data specific to this implementation
static pthread_key_t self_key;
#ifdef PthreadSupportThreadPriority
static int lowest_priority;
static int normal_priority;
static int highest_priority;
#endif /* PthreadSupportThreadPriority */
};
#endif /* __IPC_POSIX_TRAITS_H__ */

View File

@ -1,487 +0,0 @@
// Filename: ipc_ps2_traits.h
// Created by:
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef __ipc_ps2_traits_h__
#define __ipc_ps2_traits_h__
#include <stdio.h>
#include <pandabase.h>
#include <stdlib.h>
#include <eekernel.h>
#include "plist.h"
#include "pvector.h"
#include "pmap.h"
// OK. The deal with the PS2 is that there is native library thread support
// for threads and semaphors. Nothing else. This is why mutex and condition
// are based off of semaphore_class- there's no other way to have threads sleep
// (instead of spin).
// Spinning is VERY BAD on the PS2. There's no time-sharing- it's based off of
// priority. Threads are tasked out when they enter WAIT (sleep) mode. Threads
// are NOT tasked out when they're banging a while loop. If a thread is waiting
// for a variable, but not sleeping, deadlock.
class EXPCL_PANDAEXPRESS ipc_traits
{
public:
// prototype all of the classes here
class mutex_class;
class condition_class;
class semaphore_class;
class thread_class;
class library_class;
//// semaphore_class definition
class semaphore_class
{
private:
SemaParam m_sema_param;
int m_sema_id;
static const int sema_max_size = 32;
public:
static semaphore_class* const Null;
INLINE semaphore_class(const unsigned int initial = 1) {
m_sema_param.initCount = initial;
m_sema_param.maxCount = sema_max_size;
m_sema_param.option = 0;
m_sema_id = CreateSema(&m_sema_param);
if (m_sema_id < 0)
throw semaphore_fatal(-1);
}
INLINE ~semaphore_class(void) {
DeleteSema(m_sema_id);
}
INLINE void wait(void) {
int result;
result = WaitSema(m_sema_id);
// see if we overflowed the semaphore's queue
if (result != m_sema_id)
throw semaphore_fatal(-1);
}
INLINE int trywait(void) {
SemaParam sema_param;
// query the semaphor in question directly
// we can't use poll here, because if the semaphor is
// grabbable, poll will grab it.
ReferSemaStatus(m_sema_id, &sema_param);
if (sema_param.currentCount == 0)
return 1;
return 0;
}
INLINE void post(void) {
SignalSema(m_sema_id);
}
};
//// mutex_class definition
class mutex_class
{
private:
semaphore_class m_semaphore;
public:
static mutex_class* const Null;
inline mutex_class(void) {}
inline ~mutex_class(void) {}
inline void lock(void) {
m_semaphore.wait();
}
inline void unlock(void) {
m_semaphore.post();
}
};
//// condition_class definition
class condition_class
{
private:
// for an explanation of this bloody mess, see ipc_nt_traits.h
// cary's rant is more than sufficient.
class WaitingThread
{
public:
// note that the semaphor is being initialized to 0,
// meaning that a wait() on it will fail until someone
// else posts to it.
int semaphore_id;
int thread_id;
};
plist<WaitingThread> waiting_thread_list;
mutex_class list_access_lock;
mutex_class* _mutex;
public:
static condition_class* const Null;
INLINE condition_class(mutex_class *m) : _mutex(m) {}
INLINE ~condition_class(void) {}
INLINE void wait(void)
{
WaitingThread waiting_thread;
SemaParam sp;
sp.initCount = 0;
sp.maxCount = 1;
waiting_thread.semaphore_id = CreateSema(&sp);
waiting_thread.thread_id = GetThreadId();
// get the lock and add the current thread to the list.
list_access_lock.lock();
waiting_thread_list.push_back(waiting_thread);
list_access_lock.unlock();
// lock this thread away
_mutex->unlock();
WaitSema(waiting_thread.semaphore_id);
_mutex->lock();
// the thread is now sitting.
//
//
// when it gets here, it will have been released by signal/broadcast
DeleteSema(waiting_thread.semaphore_id);
}
INLINE int timedwait(const unsigned long secs,
const unsigned long nsecs) {
return -1;
}
INLINE void signal(void)
{
WaitingThread first_in_line = waiting_thread_list.front();
waiting_thread_list.pop_front();
// release this node.
SignalSema(first_in_line.semaphore_id);
}
INLINE void broadcast(void)
{
plist<WaitingThread>::iterator begin = waiting_thread_list.begin();
plist<WaitingThread>::iterator end = waiting_thread_list.end();
plist<WaitingThread>::iterator cur = begin;
int s_id;
while (cur != end)
{
// touch/release this node
s_id = (*cur).semaphore_id;
SignalSema(s_id);
cur++;
}
// and now clear the list out.
waiting_thread_list.erase(begin, end);
}
};
//// thread_class definition
class thread_class
{
private:
void *_b_ptr; // for reverse lookup
void *(*_fn)(void *);
struct ThreadParam m_thread_param;
int m_thread_id;
int m_priority;
static const int m_thread_stacksize = 16384;
char m_thread_stack[m_thread_stacksize] __attribute__ ((aligned(16)));
INLINE int priority_map(const int pri) {
switch (pri) {
case 2:
return 0;
case 0:
return 2;
case 1:
default:
return 1;
}
}
class pointer_lookup
{
public:
int thread_id;
thread_class *thread_ptr;
};
static pvector<pointer_lookup> thread_addr_vector;
static void thread_wrapper(void *);
public:
static thread_class *m_root_thread;
static void BuildRootThread(void)
{
static bool initialized = false;
// this will run once, and only once. Config calls it.
if (initialized == true)
return;
// create the new root_thread placeholder
m_root_thread = new thread_class(NULL);
m_root_thread->_fn = NULL;
m_root_thread->m_thread_id = 1;
m_root_thread->m_priority = 0;
// now add it to the pointer lookup table
pointer_lookup root_pl;
root_pl.thread_id = 1;
root_pl.thread_ptr = m_root_thread;
thread_addr_vector.push_back(root_pl);
initialized = true;
}
static thread_class* const Null;
INLINE thread_class(void *data) : _b_ptr(data) {}
INLINE ~thread_class(void) {
cout.flush();
DeleteThread(GetThreadId());
}
INLINE void manual_init(void)
{
m_thread_id = GetThreadId();
set_priority(1);
}
INLINE void start_pre(void *(*fn)(void *), const bool, const int pri)
{
_fn = fn;
m_priority = priority_map(pri);
// set up the thread_param structure
m_thread_param.entry = thread_wrapper;
m_thread_param.stack = m_thread_stack;
m_thread_param.stackSize = m_thread_stacksize;
m_thread_param.initPriority = m_priority;
m_thread_param.gpReg = &_gp;
// write this info back to the cache.
FlushCache(0);
// create and register the thread
m_thread_id = CreateThread(&m_thread_param);
if (m_thread_id < 0)
throw thread_fatal(-1);
pointer_lookup pl;
pl.thread_id = m_thread_id;
pl.thread_ptr = this;
thread_addr_vector.push_back(pl);
// start the thread
StartThread(m_thread_id, (void *) this);
}
INLINE void start_in(void) {}
INLINE void start_post(const bool det, const int) {}
INLINE void *back_ptr(void) { return _b_ptr; }
static INLINE void exit(void *)
{
int id = GetThreadId();
pvector<pointer_lookup>::iterator cur;
for (cur = thread_addr_vector.begin(); cur != thread_addr_vector.end();
cur++)
{
if ((*cur).thread_id == id)
{
thread_addr_vector.erase(cur);
break;
}
}
ExitThread();
}
// WRITE ME (or maybe ... don't?)
INLINE void join(void **status) {}
INLINE void set_priority(const int pri)
{
m_priority = priority_map(pri);
ChangeThreadPriority(m_thread_id, m_priority);
}
static INLINE thread_class *self(void)
{
int id, result;
struct ThreadParam thread_param;
pvector<pointer_lookup>::iterator cur;
id = GetThreadId();
for (cur = thread_addr_vector.begin(); cur != thread_addr_vector.end();
cur++)
{
if ((*cur).thread_id == id)
return (*cur).thread_ptr;
}
return NULL;
}
static INLINE void yield(void)
{
int id, result, priority;
struct ThreadParam thread_param;
id = GetThreadId();
result = ReferThreadStatus(id, &thread_param);
// make sure this thread isn't thrashed.
if (result != id)
throw thread_fatal(-1);
priority = thread_param.currentPriority;
RotateThreadReadyQueue(priority);
}
};
//// library_class definition
class library_class
{
public:
static library_class* const Null;
INLINE library_class(ConfigString&) {
throw lib_load_invalid();
}
INLINE ~library_class(void) {
throw lib_load_invalid();
}
INLINE void* get_symbol(ConfigString&) {
throw lib_load_invalid();
}
};
//// timing stuff
static INLINE void sleep(const unsigned long secs,
const unsigned long nsecs) {
}
static INLINE void get_time(unsigned long& abs_secs,
unsigned long& abs_nsecs,
const unsigned long rel_secs = 0,
const unsigned long rel_nsecs = 0) {
}
//// generator stuff
static INLINE mutex_class *make_mutex(void) {
return new mutex_class;
}
static INLINE condition_class *make_condition(mutex_class *m) {
return new condition_class(m);
}
static INLINE semaphore_class *make_semaphore(unsigned int initial) {
return new semaphore_class(initial);
}
static INLINE thread_class *make_thread(void *data) {
return new thread_class(data);
}
static INLINE library_class *make_library(ConfigString& str) {
return new library_class(str);
}
};
#endif // __IPC_PS2_TRAITS_H__

View File

@ -1,57 +0,0 @@
// Filename: ipc_semaphore.h
// Created by: cary (16Sep98)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef __IPC_SEMAPHORE_H__
#define __IPC_SEMAPHORE_H__
#include <pandabase.h>
#include "ipc_traits.h"
class EXPCL_PANDAEXPRESS base_semaphore {
public:
typedef ipc_traits traits;
typedef ipc_traits::semaphore_class semaphore_class;
static base_semaphore* const Null;
INLINE base_semaphore(const unsigned int initial = 1) :
_semaphore(traits::make_semaphore(initial)) {}
INLINE ~base_semaphore(void) { delete _semaphore; }
INLINE void wait(void) { _semaphore->wait(); }
INLINE int trywait(void) { return _semaphore->trywait(); }
INLINE void post(void) { _semaphore->post(); }
INLINE semaphore_class* get_semaphore(void) { return _semaphore; }
private:
semaphore_class *_semaphore;
};
class base_semaphore_lock {
public:
typedef base_semaphore semaphore;
INLINE base_semaphore_lock(semaphore& s) : _semaphore(s) {
_semaphore.wait();
}
INLINE ~base_semaphore_lock(void) { _semaphore.post(); }
private:
semaphore& _semaphore;
};
typedef base_semaphore semaphore;
typedef base_semaphore_lock semaphore_lock;
#endif /* __IPC_SEMAPHORE_H__ */

View File

@ -1,249 +0,0 @@
// Filename: ipc_solaris_traits.h
// Created by: cary (16Sep98)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef __IPC_SOLARIS_TRAITS_H__
#define __IPC_SOLARIS_TRAITS_H__
#include <pandabase.h>
#include <stdlib.h>
#include <errno.h>
#include <thread.h>
#define THROW_FATAL(x, t) throw t##_fatal(x)
#define THROW_ERRORS(x, t) { int rc = (x); \
if (rc != 0) THROW_FATAL(rc, t); }
#define THROW_ERRORS_G(x) THROW_ERRORS(x, ipc)
#define THROW_ERRORS_M(x) THROW_ERRORS(x, mutex)
#define THROW_ERRORS_C(x) THROW_ERRORS(x, condition)
#define THROW_ERRORS_S(x) THROW_ERRORS(x, semaphore)
#define THROW_ERRORS_T(x) THROW_ERRORS(x, thread)
class EXPCL_PANDAEXPRESS ipc_traits {
public:
class mutex_class;
class condition_class;
class semaphore_class;
class thread_class;
class library_class;
class mutex_class {
private:
mutex_t _mutex;
public:
// interface to mutex
static const mutex_class* Null;
INLINE mutex_class(void) {
THROW_ERRORS_M(mutex_init(&_mutex, USYNC_THREAD, 0));
}
INLINE ~mutex_class(void) {
THROW_ERRORS_M(mutex_destroy(&_mutex));
}
INLINE void lock(void) {
THROW_ERRORS_M(mutex_lock(&_mutex));
}
INLINE void unlock(void) {
THROW_ERRORS_M(mutex_unlock(&_mutex));
}
};
class condition_class {
private:
cond_t _condition;
mutex_class *_mutex;
public:
// interface to condition variables
static const condition_class* Null;
INLINE condition_class(mutex_class* m) : _mutex(m) {
THROW_ERRORS_C(cond_init(&_condition, USYNC_THREAD, 0));
}
INLINE ~condition_class(void) {
THROW_ERRORS_C(cond_destroy(&_condition));
}
INLINE void wait(void) {
THROW_ERRORS_C(cond_wait(&_condition, _mutex->get_mutex()));
}
INLINE int timedwait(const unsigned long secs,
const unsigned long nsecs) {
timespec rqts = { secs, nsecs };
int rc = cond_timedwait(&_condition, _mutexm->get_mutex(),
&rqts);
if (rc == 0)
return 1;
if (rc == ETIME)
return 0;
throw condition_fatal(rc);
}
INLINE void signal(void) {
THROW_ERRORS_C(cond_signal(&_condition));
}
INLINE void broadcast(void) {
THROW_ERRORS_C(cond_broadcast(&_condition));
}
};
class semaphore_class {
private:
sema_t _semaphore;
public:
// interface to semaphores
static const semaphore_class* Null;
INLINE semaphore_class(const unsigned int initial) {
THROW_ERRORS_S(sema_init(&_semaphore, initial, USYNC_THREAD
NULL));
}
INLINE ~semaphore_class(void) {
THROW_ERRORS_S(sema_destroy(&_semaphore));
}
INLINE void wait(void) {
THROW_ERRORS_S(sema_wait(&_semaphore));
}
INLINE int trywait(void) {
// this is way not right, but I need access to a solaris box to
// see what it really should be.
THROW_ERRORS_S(sema_trywait(&_semaphore));
}
INLINE void post(void) {
THROW_ERRORS_S(sema_post(&_semaphore));
}
};
class thread_class {
private:
thread_t _thread;
void* _b_ptr; // a handle to hang a pointer back to the high-level
// thread class on. Gross, but I couldn't think of
// a better way to do this reverse lookup.
void* (*_fn)(void*);
INLINE int priority_map(const int pri) {
switch (pri) {
case 0:
case 1:
case 2:
return pri;
}
throw thread_invalid();
// shouldn't get here, but keeps the compiler happy
return 0;
}
static void* thread_wrapper(void*);
public:
// interface to threads
static const thread_class* Null;
INLINE thread_class(void* data) : _b_ptr(data) {}
INLINE ~thread_class(void) {}
INLINE void manual_init(void) {
_thread = thr_self();
THROW_ERRORS_T(thr_setprio(_thread, priority_map(PRIORITY_NORMAL)));
}
INLINE void start_pre(void* (*fn)(void*), const bool det,
const int) {
_fn = fn;
long flags = 0;
if (det)
flags |= THR_DETACHED;
THROW_ERRORS_T(thr_create(0, 0, thread_wrapper, (void*)this,
flags, &_thread));
}
INLINE void start_in(void) {
THROW_ERRORS_T(thr_setspecific(self_key, this));
}
INLINE void start_post(const bool, const int pri) {
THROW_ERRORS_T(thr_setprio(_thread, priority_map(pri)));
}
INLINE void join(void** status) {
THROW_ERRORS_T(thr_join(_thread, (thraed_t*)NULL, status));
}
INLINE void set_priority(const int pri) {
THROW_ERRORS_T(thr_setprio(_thread, priority_map(pri)));
}
INLINE void* back_ptr(void) { return _b_ptr; }
static INLINE void exit(void* return_value) {
thr_exit(return_value);
}
static INLINE thread_class* self(void) {
thread_class* me = thread_class::Null;
THROW_ERRORS_T(thr_getspecific(self_key, (void**)&me));
return me;
}
static INLINE void yield(void) {
thr_yield();
}
};
class library_class {
public:
static library_class* const Null;
INLINE library_class(str&) {
throw lib_load_invalid();
}
INLINE ~library_class(void) {
throw lib_load_invalid();
}
INLINE void* get_symbol(str&) {
throw lib_load_invalid();
}
};
static INLINE mutex_class *make_mutex(void) {
return new mutex_class;
}
static INLINE condition_class *make_condition(mutex_class* m) {
return new condition_class(m);
}
static INLINE semaphore_class *make_semaphore(const unsigned int initial) {
return new semaphore_class(initial);
}
static INLINE thread_class *make_thread(void* data) {
return new thread_class(data);
}
static INLINE library_class *make_library(str&) {
throw lib_load_invalid();
}
static INLINE void sleep(const unsigned long secs,
const unsigned long nsecs = 0) {
timespec rqts = { secs, nsecs };
if (nanosleep(&rqts, (timespec*)NULL) != 0)
throw ipc_fatal(errno);
}
static INLINE void get_time(unsigned long& abs_secs,
unsigned long& abs_nsecs,
const unsigned long rel_secs = 0,
const unsigned long rel_nsecs = 0) {
timespec abs;
clock_gettime(CLOCK_REALTIME, &abs);
abs.tv_nsec += rel_nsecs;
abs.tv_sec += rel_secs + abs.tv_nsec / 1000000000;
abs.tv_nsec = abs.tv_nsec & 1000000000;
abs_secs = abs.tv_sec;
abs_nsecs = abs.tv_nsec;
}
static INLINE int set_atomic(int&, int) {
throw set_atomic_invalid();
}
static INLINE int inc_atomic(int&) {
throw inc_atomic_invalid();
}
static INLINE int dec_atomic(int&) {
throw dec_atomic_invalid();
}
// This should probably be private, but it is annoying to make config a
// friend
static INLINE void __set_self_key(thread_key_t k) {
self_key = k;
}
private:
// other data specific to this implementation
static thread_key_t self_key;
};
#endif /* __IPC_SOLARIS_TRAITS_H__ */

View File

@ -1,281 +0,0 @@
// Filename: ipc_thread.h
// Created by: cary (16Sep98)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef __IPC_THREAD_H__
#define __IPC_THREAD_H__
#include <pandabase.h>
#include <stdio.h>
#include "ipc_traits.h"
#include "ipc_mutex.h"
class EXPCL_PANDAEXPRESS base_thread {
public:
typedef ipc_traits traits;
typedef traits::thread_class thread_class;
typedef base_mutex mutex;
typedef base_mutex_lock mutex_lock;
// expand this to allow real priorities and scheduling. determine the
// priority limits based on the scheduling. If scheduling is not
// allowed, silently ignore those requests.
enum priority_t {
PRIORITY_LOW,
PRIORITY_NORMAL,
PRIORITY_HIGH
};
enum state_t {
STATE_NEW, // thread exists, but hasn't started yet.
STATE_RUNNING, // thread is running
STATE_TERMINATED // thread is done, but storage hasn't been reclaimed
};
static base_thread* const Null;
// Constructors set up the thread object but the thread won't start until
// start() is called. The create(...) functions can be used to construct
// and start a thread in a single call.
//
// should be able to get rid of the voids here with clever templating.
INLINE base_thread(void (*fn)(void*), void* arg = (void*)0L,
const priority_t pri = PRIORITY_NORMAL) :
_thread(thread_class::Null), _fn_void(fn), _fn_ret(0L), _mutex(),
_state(STATE_NEW), _priority(pri), _thread_arg(arg), _detached(true) {
common_constructor();
}
INLINE base_thread(void* (*fn)(void*), void* arg = (void*)0L,
const priority_t pri = PRIORITY_NORMAL) :
_thread(thread_class::Null), _fn_void(0L), _fn_ret(fn), _mutex(),
_state(STATE_NEW), _priority(pri), _thread_arg(arg), _detached(false) {
common_constructor();
}
// causes this thread to start executing
INLINE void start(void) {
mutex_lock l(_mutex);
if (_state != STATE_NEW) {
cerr << "base_thread::start throwing thread_invalid()" << endl;
#ifdef BROKEN_EXCEPTIONS
return;
#else
throw thread_invalid();
#endif /* BROKEN_EXCEPTIONS */
}
_thread = traits::make_thread(this);
_thread->start_pre(thread_wrapper, _detached, _priority);
_state = STATE_RUNNING;
_thread->start_post(_detached, _priority);
}
// causes the calling thread to wait for this thread's completion,
// putting the return value in the space passed by the parameter. Only
// undetached threads may be joined. Storage for the thread will be
// reclaimed when it exits.
// Again, clever templating should be able to eliminate this void
// nonsense. It's gross!
INLINE void join(void** status) {
_mutex.lock();
if ((_state != STATE_RUNNING) && (_state != STATE_TERMINATED)) {
_mutex.unlock();
#ifdef BROKEN_EXCEPTIONS
return;
#else
throw thread_invalid();
#endif /* BROKEN_EXCEPTIONS */
}
_mutex.unlock();
if (this == self())
#ifdef BROKEN_EXCEPTIONS
return;
#else
throw thread_invalid();
#endif /* BROKEN_EXCEPTIONS */
if (_detached)
#ifdef BROKEN_EXCEPTIONS
return;
#else
throw thread_invalid();
#endif /* BROKEN_EXCEPTIONS */
_thread->join(status);
delete this;
}
// set the priority of this thread
INLINE void set_priority(const priority_t pri) {
mutex_lock l(_mutex);
if (_state != STATE_RUNNING)
#ifdef BROKEN_EXCEPTIONS
return;
#else
throw thread_invalid();
#endif /* BROKEN_EXCEPTIONS */
_thread->set_priority(pri);
_priority = pri;
}
// return this thread's priority
INLINE priority_t get_priority(void) {
mutex_lock l(_mutex);
// in a more general priority system, we should check that the thread
// is running at the priority we think it is.
return _priority;
}
// return this thread's state
INLINE state_t get_state(void) {
mutex_lock l(_mutex);
return _state;
}
// return this thread's id within the current process
INLINE int get_id(void) {
return _id; // presumably this doesn't change
}
// causes the calling thread to exit, again the void action here is
// unhappy.
static INLINE void exit(void* return_value = (void*)0L) {
cout.flush();
base_thread* me = self();
if (me != (base_thread*)0L) {
me->_mutex.lock();
// if (me->_state != STATE_RUNNING) non-fatal error
me->_state = STATE_TERMINATED;
me->_mutex.unlock();
if (me->_detached)
delete me;
}
thread_class::exit(return_value);
}
// returns the caller's thread object. If the calling thread is not the
// main thread or created by us, thread_class::Null is returned
static INLINE base_thread* self(void) {
cout.flush();
thread_class* tclass=thread_class::self();
base_thread* ret=(base_thread*)0L;
if (tclass != thread_class::Null)
ret = (base_thread*)(tclass->back_ptr());
return ret;
}
// calling task releasing control to the scheduler
static INLINE void yield(void) {
thread_class::yield();
}
// sleep for the specified amount of time
static INLINE void sleep(const unsigned long secs,
const unsigned long nsecs = 0) {
traits::sleep(secs, nsecs);
}
// 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 INLINE void get_time(unsigned long& abs_secs,
unsigned long& abs_nsecs,
const unsigned long rel_secs = 0,
const unsigned long rel_nsecs = 0) {
traits::get_time(abs_secs, abs_nsecs, rel_secs, rel_nsecs);
}
// shortcut function to create and start a thread in one call
static INLINE base_thread* create(void (*fn)(void*),
void* arg = (void*)0L,
const priority_t pri=PRIORITY_NORMAL) {
base_thread* t = new base_thread(fn, arg, pri);
t->start();
return t;
}
static INLINE base_thread* create(void* (*fn)(void*),
void* arg = (void*)0L,
const priority_t pri=PRIORITY_NORMAL) {
base_thread* t = new base_thread(fn, arg, pri);
t->start();
return t;
}
// a handle to the implementation specific thread, this really should
// NEVER be called from user code.
INLINE thread_class* get_thread(void) { return _thread; }
protected:
// 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.
INLINE base_thread(void* arg = (void*)0L,
const priority_t pri = PRIORITY_NORMAL) :
_thread(thread_class::Null), _fn_void(0L), _fn_ret(0L), _mutex(),
_state(STATE_NEW), _priority(pri), _thread_arg(arg), _detached(true) {
common_constructor();
}
// 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.
INLINE void start_undetached(void) {
if ((_fn_void != NULL) || (_fn_ret != NULL))
#ifdef BROKEN_EXCEPTIONS
return;
#else
throw thread_invalid();
#endif /* BROKEN_EXCEPTIONS */
_detached = false;
start();
}
// destructor cannot be called by user (except via a derived class).
// Use exit() 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 thread<...> shouldn't be
// public either (otherwise the thread object can be destroyed while the
// underlying thread is still running (this is Bad(tm))).
virtual ~base_thread(void) {
delete _thread;
}
private:
thread_class *_thread; // the implementation specific thread
void (*_fn_void)(void*);
void* (*_fn_ret)(void*);
mutex _mutex; // used to protect members which can change after
// construction. ie: _state and _priority
state_t _state;
priority_t _priority;
int _id;
void* _thread_arg;
bool _detached;
static mutex* _next_id_mutex;
static int _next_id;
// can be overridden in a derived class. When constructed using the
// constructor thread(void*, priority_t), these functions are called by
// start() and start_undetached() respectively.
virtual void run(void*);
virtual void* run_undetached(void*);
// implements the common parts of the constructors
INLINE void common_constructor(void) {
if (_next_id_mutex == (mutex *)0L) {
// ok, we're the first in here.
_next_id_mutex = new mutex;
base_thread* t = new base_thread;
if (t->_state != STATE_NEW) {
// FATAL() << "thread initialization: problem creating initial thread object" << nend;
::exit(1);
}
t->_state = STATE_RUNNING;
t->_thread = traits::make_thread(t);
t->_thread->manual_init();
t->_thread->start_in();
}
mutex_lock l(*_next_id_mutex);
_id = _next_id++;
}
static void *thread_wrapper(void*);
};
typedef base_thread thread;
#endif /* __IPC_THREAD_H__ */

View File

@ -1,268 +0,0 @@
// Filename: ipc_traits.cxx
// Created by: frang (06Apr00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "ipc_traits.h"
Configure(ipc_trait);
#if (__IPC_FLAVOR_DUJOUR_TOKEN__ == 0)
// mach
ipc_traits::mutex_class* const ipc_traits::mutex_class::Null =
(ipc_traits::mutex_class*)0L;
ipc_traits::condition_class* const ipc_traits::condition_class::Null =
(ipc_traits::condition_class*)0L;
ipc_traits::semaphore_class* const ipc_traits::semaphore_class::Null =
(ipc_traits::semaphore_class*)0L;
ipc_traits::thread_class* const ipc_traits::thread_class::Null =
(ipc_traits::thread_class*)0L;
ipc_traits::library_class* const ipc_traits::library_class::Null =
(ipc_traits::library_class*)0L;
int ipc_traits::normal_priority;
int ipc_traits::highest_priority;
ConfigureFn(ipc_trait) {
// find base and max priority. This is the inital 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) {
FATAL() << "ipc_traits(mach) initialization: error determining thread_info"
<< nend;
::exit(1);
} else {
ipc_traits::__set_normal_priority(info.base_priority);
ipc_traits::__set_highest_priority(info.max_priority);
}
}
void* ipc_traits::thread_class::thread_wrapper(void* data) {
ipc_traits::thread_class* me = (ipc_traits::thread_class*)data;
return (*me->_fn)(me->_b_ptr);
}
#elif (__IPC_FLAVOR_DUJOUR_TOKEN__ == 1)
// NT
ipc_traits::mutex_class* const ipc_traits::mutex_class::Null =
(ipc_traits::mutex_class*)0L;
ipc_traits::condition_class* const ipc_traits::condition_class::Null =
(ipc_traits::condition_class*)0L;
ipc_traits::semaphore_class* const ipc_traits::semaphore_class::Null =
(ipc_traits::semaphore_class*)0L;
ipc_traits::thread_class* const ipc_traits::thread_class::Null =
(ipc_traits::thread_class*)0L;
ipc_traits::library_class* const ipc_traits::library_class::Null =
(ipc_traits::library_class*)0L;
DWORD ipc_traits::self_tls_index;
ipc_traits::condition_class::_internal_thread_dummy*
ipc_traits::condition_class::_internal_thread_helper::cache =
(ipc_traits::condition_class::_internal_thread_dummy*)0L;
ipc_traits::mutex_class*
ipc_traits::condition_class::_internal_thread_helper::cachelock =
(ipc_traits::mutex_class*)0L;
ConfigureFn(ipc_trait) {
DWORD tmp = TlsAlloc();
if (tmp == 0xffffffff)
throw ipc_fatal(GetLastError());
ipc_traigs::__set_self_tls_index(tmp);
}
#ifndef __BCPLUSPLUS__
unsigned _stdcall ipc_traits::thread_class::thread_wrapper(void* data) {
#else /* __BCPLUSPLUS__ */
void _USERENTRY ipc_traits::thread_class::thread_wrapper(void* data) {
#endif /* __BCPLUSPLUS__ */
ipc_traits::thread_class* me = (ipc_traits::thread_class*)data;
me->_return_value = (*me->_fn)(me->_b_ptr);
#ifndef __BCPLUSPLUS__
return 0;
#endif /* __BCPLUSPLUS__ */
}
#elif (__IPC_FLAVOR_DUJOUR_TOKEN__ == 2)
// posix
ipc_traits::mutex_class* const ipc_traits::mutex_class::Null =
(ipc_traits::mutex_class*)0L;
ipc_traits::condition_class* const ipc_traits::condition_class::Null =
(ipc_traits::condition_class*)0L;
ipc_traits::semaphore_class* const ipc_traits::semaphore_class::Null =
(ipc_traits::semaphore_class*)0L;
ipc_traits::thread_class* const ipc_traits::thread_class::Null =
(ipc_traits::thread_class*)0L;
ipc_traits::library_class* const ipc_traits::library_class::Null =
(ipc_traits::library_class*)0L;
pthread_key_t ipc_traits::self_key;
#ifdef PthreadSupportThreadPriority
int ipc_traits::lowest_priority;
int ipc_traits::normal_priority;
int ipc_traits::highest_priority;
#endif /* PthreadSupportThreadPriority */
ConfigureFn(ipc_trait) {
#ifdef NeedPthreadInit
pthread_init();
#endif /* NeedPthreadInit */
pthread_key_t ktmp;
#if (PthreadDraftVersion == 4)
THROW_ERRORS_G(pthread_keycreate(&ktmp, NULL));
#else /* PthreadDraftVersion 4 */
THROW_ERRORS_G(pthread_key_create(&ktmp, NULL));
#endif /* PthreadDraftVersion 4 */
ipc_traits::__set_self_key(ktmp);
#ifdef PthreadSupportThreadPriority
int plow, pnorm, phigh;
#if defined(__osf1__) && defined(__alpha__) || defined(__VMS)
plow = PRI_OTHER_MIN;
phigh = PRI_OTHER_MAX;
#elif defined(__hpux__)
plow = PRI_OTHER_MIN;
phigh = PRI_OTHER_MAX;
#elif defined(__sunos__) && (__OSVERSION__ == 5)
// a bug in pthread_attr_setschedparam means lowest priority is 1 not 0
plow = 1;
phigh = 3;
#else /* os testing */
plow = sched_get_priority_min(SCHED_FIFO);
phigh = sched_get_priority_max(SCHED_FIFO);
#endif /* os testing */
switch (phigh - plow) {
case 0:
case 1:
pnorm = plow;
break;
default:
pnorm = plow + 1;
break;
}
ipc_traits::__set_lowest_priority(plow);
ipc_traits::__set_normal_priority(pnorm);
ipc_traits::__set_highest_priority(phigh);
#endif /* PthreadSupportThreadPriority */
}
void* ipc_traits::thread_class::thread_wrapper(void* data) {
ipc_traits::thread_class* me = (ipc_traits::thread_class*)data;
return (*me->_fn)(me->_b_ptr);
}
#elif (__IPC_FLAVOR_DUJOUR_TOKEN__ == 3)
// solaris
ipc_traits::mutex_class* const ipc_traits::mutex_class::Null =
(ipc_traits::mutex_class*)0L;
ipc_traits::condition_class* const ipc_traits::condition_class::Null =
(ipc_traits::condition_class*)0L;
ipc_traits::semaphore_class* const ipc_traits::semaphore_class::Null =
(ipc_traits::semaphore_class*)0L;
ipc_traits::thread_class* const ipc_traits::thread_class::Null =
(ipc_traits::thread_class*)0L;
ipc_traits::library_class* const ipc_traits::library_class::Null =
(ipc_traits::library_class*)0L;
thread_key_t ipc_traits::self_key;
ConfigureFn(ipc_trait) {
thread_key_t ktmp;
THROW_ERRORS_G(thr_keycreate(&ktmp, NULL));
ipc_traits::__set_self_key(ktmp);
}
void* ipc_traits::thread_class::thread_wrapper(void* data) {
ipc_traits::thread_class* me = (ipc_traits::thread_class*)data;
return (*me->_fn)(me->_b_ptr);
}
#elif (__IPC_FLAVOR_DUJOUR_TOKEN__ == 4)
// NSPR
ipc_traits::mutex_class* const ipc_traits::mutex_class::Null =
(ipc_traits::mutex_class*)0L;
ipc_traits::condition_class* const ipc_traits::condition_class::Null =
(ipc_traits::condition_class*)0L;
ipc_traits::semaphore_class* const ipc_traits::semaphore_class::Null =
(ipc_traits::semaphore_class*)0L;
ipc_traits::thread_class* const ipc_traits::thread_class::Null =
(ipc_traits::thread_class*)0L;
ipc_traits::library_class* const ipc_traits::library_class::Null =
(ipc_traits::library_class*)0L;
PRUintn ipc_traits::_data_index;
ConfigureFn(ipc_trait) {
PRUintn tmp;
PR_NewThreadPrivateIndex(&tmp, (PRThreadPrivateDTOR)0L);
ipc_traits::__set_data_index(tmp);
}
void ipc_traits::thread_class::thread_wrapper(void* data) {
ipc_traits::thread_class* me = (ipc_traits::thread_class*)data;
me->_return_value = (*me->_fn)(me->_b_ptr);
}
#elif (__IPC_FLAVOR_DUJOUR_TOKEN__ == 5)
// PS2
#include <eekernel.h>
#include "pmap.h"
ConfigureFn(ipc_trait) {
ipc_traits::thread_class::BuildRootThread();
}
pvector<ipc_traits::thread_class::pointer_lookup> ipc_traits::thread_class::thread_addr_vector;
ipc_traits::thread_class *ipc_traits::thread_class::m_root_thread;
ipc_traits::mutex_class* const ipc_traits::mutex_class::Null =
(ipc_traits::mutex_class *) 0L;
ipc_traits::condition_class* const ipc_traits::condition_class::Null =
(ipc_traits::condition_class *) 0L;
ipc_traits::semaphore_class* const ipc_traits::semaphore_class::Null =
(ipc_traits::semaphore_class *) 0L;
ipc_traits::thread_class* const ipc_traits::thread_class::Null =
(ipc_traits::thread_class *) 0L;
ipc_traits::library_class* const ipc_traits::library_class::Null =
(ipc_traits::library_class *) 0L;
void ipc_traits::thread_class::thread_wrapper(void *data) {
ipc_traits::thread_class *me = (ipc_traits::thread_class *) data;
(*me->_fn)(me->_b_ptr);
}
#else /* out of flavor tokens */
#error "invalid ipc flavor token"
#endif /* out of flavor tokens */

View File

@ -1,229 +0,0 @@
// Filename: ipc_traits.h
// Created by: cary (16Sep98)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef __IPC_TRAITS_H__
#define __IPC_TRAITS_H__
#include <pandabase.h>
#include <string>
// decide which IPC implementation to use. This is so much fun, I just can't
// hardly stand it.
// Flavor tokens:
// 0 - mach
// 1 - nt
// 2 - posix
// 3 - solaris
// 4 - NSPR
// 5 - PS2
// I threw PS2 in first because sometimes other env vars are set, but if PENV is PS2,
// we're NEVER building anything else... CSN
#if defined(PENV_PS2)
#define __IPC_FLAVOR_DUJOUR__ PS2
#define __IPC_FLAVOR_DUJOUR_TOKEN__ 5
#elif defined(HAVE_NSPR)
#define __IPC_FLAVOR_DUJOUR__ nspr
#define __IPC_FLAVOR_DUJOUR_TOKEN__ 4
#elif defined(__arm__) && defined(__atmos__)
#define __IPC_FLAVOR_DUJOUR__ posix
#define __IPC_FLAVOR_DUJOUR_TOKEN__ 2
#elif defined(__alpha__) && defined(__osf1__)
#define __IPC_FLAVOR_DUJOUR__ posix
#define __IPC_FLAVOR_DUJOUR_TOKEN__ 2
#elif defined(__powerpc__) && defined(__aix__)
#define __IPC_FLAVOR_DUJOUR__ posix
#define __IPC_FLAVOR_DUJOUR_TOKEN__ 2
#elif defined(__hpux__)
#define __IPC_FLAVOR_DUJOUR__ posix
#define __IPC_FLAVOR_DUJOUR_TOKEN__ 2
#elif defined(WIN32_VC)
#define __IPC_FLAVOR_DUJOUR__ nt
#define __IPC_FLAVOR_DUJOUR_TOKEN__ 1
#elif defined(__sun__)
#ifdef UsePthreads
#define __IPC_FLAVOR_DUJOUR__ posix
#define __IPC_FLAVOR_DUJOUR_TOKEN__ 2
#else
#define __IPC_FLAVOR_DUJOUR__ solaris
#define __IPC_FLAVOR_DUJOUR_TOKEN__ 3
#endif /* UsePthreads */
#elif defined(__linux__)
#define __IPC_FLAVOR_DUJOUR__ posix
#define __IPC_FLAVOR_DUJOUR_TOKEN__ 2
#elif defined(__nextstep__)
#define __IPC_FLAVOR_DUJOUR__ mach
#define __IPC_FLAVOR_DUJOUR_TOKEN__ 0
#elif defined(__VMS)
#define __IPC_FLAVOR_DUJOUR__ posix
#define __IPC_FLAVOR_DUJOUR_TOKEN__ 2
#elif defined(__SINIX__)
#define __IPC_FLAVOR_DUJOUR__ posix
#define __IPC_FLAVOR_DUJOUR_TOKEN__ 2
#elif defined(__sgi)
#define __IPC_FLAVOR_DUJOUR__ posix
#define __IPC_FLAVOR_DUJOUR_TOKEN__ 2
#else
#error "Unable to determine which IPC implementation to use"
#endif /* OS identification */
// this exception is a general fatal exception from the IPC code
class EXPCL_PANDAEXPRESS ipc_fatal {
public:
int error;
INLINE ipc_fatal(const int e = 0) : error(e) {}
};
// this exception is a general invalid value/function call exception for the
// IPC code
class EXPCL_PANDAEXPRESS ipc_invalid {};
// this exception is thrown in the event of a fatal error in the mutex code
class EXPCL_PANDAEXPRESS mutex_fatal : public ipc_fatal {
public:
INLINE mutex_fatal(const int e = 0) : ipc_fatal(e) {}
};
// this exception is thrown when a mutex is called in an invalid state, or the
// arguments to the call are invalid
class EXPCL_PANDAEXPRESS mutex_invalid : public ipc_invalid {};
// this exception is thrown in the event of a fatal error in the condition
// variable code
class EXPCL_PANDAEXPRESS condition_fatal : public ipc_fatal {
public:
INLINE condition_fatal(const int e = 0) : ipc_fatal(e) {}
};
// this exception is thrown when a condition variable is called in an
// invalid state, or the arguments to the call are invalid
class EXPCL_PANDAEXPRESS condition_invalid : public ipc_invalid {};
// this exception is thrown in the event of a fatal error in the semaphore code
class EXPCL_PANDAEXPRESS semaphore_fatal : public ipc_fatal {
public:
INLINE semaphore_fatal(const int e = 0) : ipc_fatal(e) {}
};
// this exception is thrown when a semaphore is called in an invalid state, or
// the arguments to the call are invalid
class EXPCL_PANDAEXPRESS semaphore_invalid : public ipc_invalid {};
// this exception is thrown in the event of a fatal error in the thread code
class EXPCL_PANDAEXPRESS thread_fatal : public ipc_fatal {
public:
INLINE thread_fatal(const int e = 0) : ipc_fatal(e) {}
};
// this exception is thrown when a thread is called in an invalid state, or
// the arguments to the call are invalid
class EXPCL_PANDAEXPRESS thread_invalid : public ipc_invalid {};
// this exception is thrown in the event of a fatal error in the atomic set
// code
class EXPCL_PANDAEXPRESS set_atomic_fatal : public ipc_fatal {
public:
INLINE set_atomic_fatal(const int e = 0) : ipc_fatal(e) {}
};
// this exception is thrown when an atomic set is called in an invalid state,
// or the arguments to the call are invalid
class EXPCL_PANDAEXPRESS set_atomic_invalid : public ipc_invalid {};
// this exception is thrown in the event of a fatal error in the atomic
// increment code
class EXPCL_PANDAEXPRESS inc_atomic_fatal : public ipc_fatal {
public:
INLINE inc_atomic_fatal(const int e = 0) : ipc_fatal(e) {}
};
// this exception is thrown when an atomic increment is called in an invalid
// state, or the arguments to the call are invalid
class EXPCL_PANDAEXPRESS inc_atomic_invalid : public ipc_invalid {};
// this exception is thrown in the event of a fatal error in the atomic
// decrement code
class EXPCL_PANDAEXPRESS dec_atomic_fatal : public ipc_fatal {
public:
INLINE dec_atomic_fatal(const int e = 0) : ipc_fatal(e) {}
};
// this exception is thrown when an atomic decrement is called in an invalid
// state, or the arguments to the call are invalid
class EXPCL_PANDAEXPRESS dec_atomic_invalid : public ipc_invalid {};
// this exception is thrown in the event of a fatal error in the library load
// code
class EXPCL_PANDAEXPRESS lib_load_fatal : public ipc_fatal {
public:
INLINE lib_load_fatal(const int e = 0) : ipc_fatal(e) {}
};
// this exception is thrown when a library load is called in an invalid state,
// or the arguments to the call are invalid
class EXPCL_PANDAEXPRESS lib_load_invalid : public ipc_invalid {};
#include <dconfig.h>
#if (__IPC_FLAVOR_DUJOUR_TOKEN__ == 0)
#include "ipc_mach_traits.h"
#elif (__IPC_FLAVOR_DUJOUR_TOKEN__ == 1)
#include "ipc_nt_traits.h"
#elif (__IPC_FLAVOR_DUJOUR_TOKEN__ == 2)
#include "ipc_posix_traits.h"
#elif (__IPC_FLAVOR_DUJOUR_TOKEN__ == 3)
#include "ipc_solaris_traits.h"
#elif (__IPC_FLAVOR_DUJOUR_TOKEN__ == 4)
#include "ipc_nspr_traits.h"
#elif (__IPC_FLAVOR_DUJOUR_TOKEN__ == 5)
#include "ipc_ps2_traits.h"
#else
#error "invalid ipc flavor token"
#endif /* loading trait specializations */
#endif /* __IPC_TRAITS_H__ */

View File

@ -1,85 +0,0 @@
// Filename: loom.cxx
// Created by: cary (23Sep98)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "loom_internal.h"
#include <algo.h>
void app_service::DoIt(void* data)
{
Action ret;
app_service* me = (app_service*)data;
unsigned long s = 0, n = 0;
condition_variable* c = condition_variable::Null;
me->_thread = thread::self();
if (me->_init != NULL)
(*me->_init)();
while ((ret = (*me->_service)(s, n, c)) != DONE) {
switch (ret) {
case RESERVICE:
break; // we're about to do this anyway
case YIELD:
thread::yield();
break;
case SLEEP:
thread::sleep(s, n);
s = n = 0;
break;
case WAIT:
c->wait();
c = condition_variable::Null;
break;
}
}
if (me->_cleanup != NULL)
(*me->_cleanup)();
{
mutex_lock l(*main_thread_mutex);
me->_thread = thread::Null;
service_list::iterator i=find(task_list->begin(), task_list->end(), me);
if (i == task_list->end())
throw thread_fatal(-1);
task_list->erase(i);
}
thread::exit(NULL);
}
void RegisterAppService(vv_func init, av_func service, vv_func cleanup,
vv_func info)
{
app_service* app = new app_service(init, service, cleanup, info);
if (task_list == (service_list *)0L) {
task_list = new service_list;
main_thread_mutex = new mutex;
}
mutex_lock l(*main_thread_mutex);
task_list->push_back(app);
}
void SendMainThreadMessage(main_thread_message& m)
{
main_thread_message *mess = new main_thread_message(m);
{
mutex_lock l(*message_mutex);
while (!main_thread_empty_flag)
main_thread_empty->wait();
message_to_main_thread = mess;
main_thread_empty_flag = false;
main_thread_full->signal();
}
}

View File

@ -1,74 +0,0 @@
// Filename: loom.h
// Created by: cary (23Sep98)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef __LOOM_H__
#define __LOOM_H__
#include <pandabase.h>
#include "ipc_mutex.h"
#include "ipc_condition.h"
extern mutex main_thread_print_mutex;
// interface to modules for being runable from app.
enum Action { RESERVICE, DONE, YIELD, SLEEP, WAIT };
typedef void (*vv_func)(void);
typedef Action (*av_func)(unsigned long&, unsigned long&, condition_variable*&);
// parameters in order are:
// initialization function - setup and data that the service function might
// need in order to run
// service function - perform the task of this thing. Either incrementally
// (thus returning RESERVICE), or all at once (handling
// yielding and waiting internally and returning DONE
// when all it's work is complete).
// cleanup function - when the service function returns DONE, if this is not
// NULL, this function will be called to cleanup whatever
// is left to be done by this task.
// info function - if not NULL and the main thread is asked to tell about
// what's running, this function will be called. It is
// expected that it will output something usefull about what
// the task is and what it's doing.
extern void RegisterAppService(vv_func, av_func, vv_func = (vv_func)0L,
vv_func = (vv_func)0L);
template <class str = std::string>
class main_thread_message_base {
public:
enum message_t { LOAD, RESCAN, INFO };
INLINE main_thread_message_base(const message_t message, str s = "") :
_m(message), _lib(s) {}
INLINE main_thread_message_base(const main_thread_message_base& m) :
_m(m._m), _lib(m._lib) {}
INLINE ~main_thread_message_base(void) {}
INLINE message_t get_message(void) const { return _m; }
INLINE str get_lib(void) const { return _lib; }
private:
message_t _m;
str _lib;
};
typedef main_thread_message_base<> main_thread_message;
extern void SendMainThreadMessage(main_thread_message&);
#endif /* __LOOM_H__ */

View File

@ -1,88 +0,0 @@
// Filename: loom_internal.h
// Created by: cary (23Sep98)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef __LOOM_INTERNAL_H__
#define __LOOM_INTERNAL_H__
#include <pandabase.h>
#include "loom.h"
#include "ipc_mutex.h"
#include "ipc_condition.h"
#include "ipc_thread.h"
#include "plist.h"
class app_service;
typedef std::plist<app_service*> service_list;
extern service_list *task_list;
extern mutex *main_thread_mutex;
class app_service {
private:
vv_func _init, _cleanup, _info;
av_func _service;
thread* _thread;
INLINE app_service(void) {}
INLINE ~app_service(void) {}
static void DoIt(void*);
public:
INLINE app_service(vv_func init, av_func service, vv_func cleanup,
vv_func info) : _init(init), _service(service),
_cleanup(cleanup), _info(info), _thread(thread::Null)
{}
INLINE bool started() {
return (_thread != thread::Null);
}
INLINE void start(void) {
if (!this->started())
thread::create(DoIt, (void*)this);
}
INLINE void info(void) {
// this probably should mutex lock the task_list while checking things
if (_info != (vv_func)0L)
(*_info)();
if (_thread != thread::Null) {
cerr << "thread is currently running. Id = " << _thread->get_id()
<< ". Current state = ";
switch (_thread->get_state()) {
case thread::STATE_NEW:
cerr << "New.";
break;
case thread::STATE_RUNNING:
cerr << "Running.";
break;
case thread::STATE_TERMINATED:
cerr << "Terminated";
break;
}
cerr << endl;
} else
cerr << "thread not started or created yet." << endl;
}
};
extern main_thread_message* message_to_main_thread;
extern mutex* message_mutex;
extern condition_variable* main_thread_full;
extern condition_variable* main_thread_empty;
extern bool main_thread_empty_flag;
#endif /* __LOOM_INTERNAL_H__ */

View File

@ -1,97 +0,0 @@
// Filename: loom_main.cxx
// Created by: cary (23Sep98)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "loom_internal.h"
#include <dconfig.h>
#include <load_dso.h>
#include <filename.h>
#include <string>
mutex main_thread_print_mutex;
service_list *task_list = (service_list *)0L;
mutex *main_thread_mutex = mutex::Null;
main_thread_message* message_to_main_thread = (main_thread_message*)0L;
mutex *message_mutex;
condition_variable* main_thread_full = condition_variable::Null;
condition_variable* main_thread_empty = condition_variable::Null;
bool main_thread_empty_flag;
int main(int argc, char** argv)
{
for (int i=0; i<argc; ++i)
if (argv[i] != (char*)0L) {
Filename filename = argv[i];
if (filename.get_extension() == ".so") {
filename.set_type(Filename::T_dso);
load_dso(filename);
}
}
if (task_list == (service_list*)0L) {
// really, this shouldn't happen. But if none of the loaded SOs do
// anything, well, we should just exit.
cerr << "None of the loaded SOs had any work to do." << endl;
return 0;
}
message_mutex = new mutex;
main_thread_full = new condition_variable(*message_mutex);
main_thread_empty = new condition_variable(*message_mutex);
main_thread_empty_flag = true;
main_thread_mutex->lock();
service_list::iterator j;
for (j=task_list->begin(); j!=task_list->end(); ++j)
(*j)->start();
main_thread_mutex->unlock();
while (!task_list->empty()) {
unsigned long s, n;
mutex_lock l(*message_mutex);
thread::get_time(s, n, 2, 0); // 2 seconds from now
main_thread_full->timedwait(s, n);
if (!main_thread_empty_flag) {
switch (message_to_main_thread->get_message()) {
case main_thread_message::LOAD:
{
Filename filename = message_to_main_thread->get_lib();
filename.set_type(Filename::F_dso);
load_dso(filename);
}
case main_thread_message::RESCAN:
for (j=task_list->begin(); j!=task_list->end(); ++j)
(*j)->start();
break;
case main_thread_message::INFO:
for (j=task_list->begin(); j!=task_list->end(); ++j)
(*j)->info();
break;
default:
// really should never be here
break;
}
delete message_to_main_thread;
message_to_main_thread = (main_thread_message*)0L;
main_thread_empty_flag = true;
main_thread_empty->signal();
}
}
thread::sleep(0, 500000000); // give some time for cleanup (1/2 sec)
thread::exit(NULL);
}

View File

@ -1,163 +0,0 @@
// Filename: loom_test1.cxx
// Created by: cary (30Sep98)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "loom.h"
#include <dconfig.h>
static int test1_phase;
static int test1_phase2;
static mutex loom_test1_mutex;
static condition_variable loom_test1_cond(loom_test1_mutex);
#define PRINT(x) { mutex_lock l(main_thread_print_mutex); x; }
void loom_test1_init2(void)
{
PRINT(cerr << "In loom_test1_init2" << endl);
test1_phase2 = 0;
}
Action loom_test1_service2(unsigned long& s, unsigned long& n,
condition_variable*&)
{
if (test1_phase2 == 0) {
test1_phase2 = 1;
s = 4;
PRINT(cerr << "loom_test1_service2: sleeping for 4 seconds" << endl);
return SLEEP;
} else if (test1_phase2 == 1) {
test1_phase2 = 2;
PRINT(cerr << "loom_test1_service2: signaling loom_test1_service to continue" << endl);
loom_test1_cond.signal();
n = 500000000;
PRINT(cerr << "loom_test1_service2: sleeping for 1/2 second" << endl);
return SLEEP;
} else if (test1_phase2 == 2) {
test1_phase2 = 3;
PRINT(cerr << "loom_test1_service2: sending INFO message to main thread" << endl);
main_thread_message m(main_thread_message::INFO);
SendMainThreadMessage(m);
PRINT(cerr << "loom_test1_service2: returning RESERVICE" << endl);
return RESERVICE;
} else if (test1_phase2 == 3) {
if (test1_phase < 19) {
PRINT(cerr << "loom_test1_service2: returning RESERVICE" << endl);
return RESERVICE;
} else {
test1_phase2 = 4;
PRINT(cerr << "loom_test1_service2: sending INFO message to main thread" << endl);
main_thread_message m(main_thread_message::INFO);
SendMainThreadMessage(m);
PRINT(cerr << "loom_test1_service2: sleeping for 3/4 second" << endl);
n = 750000000;
return SLEEP;
}
} else {
PRINT(cerr << "loom_test1_service2: returning DONE" << endl);
return DONE;
}
}
void loom_test1_cleanup2(void)
{
PRINT(cerr << "In loom_test1_cleanup2" << endl);
}
void loom_test1_init(void)
{
PRINT(cerr << "In loom_test1_init" << endl);
test1_phase = 0;
}
Action loom_test1_service(unsigned long& s, unsigned long& n,
condition_variable*& c)
{
++test1_phase;
switch (test1_phase) {
case 5:
PRINT(cerr << "loom_test1_service: returning YIELD to service manager" << endl);
return YIELD;
case 7:
s = 5;
PRINT(cerr << "loom_test1_service: returning SLEEP to service manager (s=5)" << endl);
return SLEEP;
case 9:
PRINT(cerr << "loom_test1_service: registering loom_test1_service2, etc, and returning YIELD" << endl);
RegisterAppService(loom_test1_init2, loom_test1_service2, loom_test1_cleanup2);
return YIELD;
case 11:
{
PRINT(cerr << "loom_test1_service: sending RESCAN message to main thread, returning YIELD" << endl);
main_thread_message m(main_thread_message::RESCAN);
SendMainThreadMessage(m);
return YIELD;
}
case 13:
PRINT(cerr << "loom_test1_service: returning WAIT to service manager" << endl);
loom_test1_mutex.lock();
c = &loom_test1_cond;
return WAIT;
case 15:
n = 500000000;
PRINT(cerr << "loom_test1_service: returning SLEEP (n=500000000)" << endl);
return SLEEP;
case 17:
{
PRINT(cerr << "loom_test1_service: sending LOAD message to main thread (libloom_test2.so)" << endl);
main_thread_message m(main_thread_message::LOAD, "libloom_test2.so");
SendMainThreadMessage(m);
s = 3;
PRINT(cerr << "loom_test1_service: returning SLEEP (s=3)" << endl);
return SLEEP;
}
case 19:
{
PRINT(cerr << "loom_test1_service: sending INFO message to main thread" << endl);
main_thread_message m(main_thread_message::INFO);
SendMainThreadMessage(m);
n = 500000000;
PRINT(cerr << "loom_test1_service: returning SLEEP (s=3)" << endl);
return SLEEP;
}
case 23:
PRINT(cerr << "loom_test1_service: returning DONE to service manager" << endl);
return DONE;
default:
PRINT(cerr << "loom_test1_service: returning RESERVICE to service manager" << endl);
return RESERVICE;
};
}
void loom_test1_cleanup(void)
{
PRINT(cerr << "In loom_test1_cleanup" << endl);
}
void loom_test1_info(void)
{
PRINT(cerr << "Loom_test1_info function (phase = " << test1_phase << ")" << endl);
}
Configure(loom_test1);
ConfigureFn(loom_test1)
{
RegisterAppService(loom_test1_init, loom_test1_service, loom_test1_cleanup,
loom_test1_info);
}

View File

@ -1,54 +0,0 @@
// Filename: loom_test2.cxx
// Created by: cary (30Sep98)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "loom.h"
#include <dconfig.h>
static int test2_phase;
#define PRINT(x) { mutex_lock l(main_thread_print_mutex); x; }
void loom_test2_init(void)
{
PRINT(cerr << "In loom_test2_init" << endl);
test2_phase = 0;
}
Action loom_test2_service(unsigned long& s, unsigned long&,
condition_variable*&)
{
++test2_phase;
switch (test2_phase) {
case 0:
s = 5;
PRINT(cerr << "loom_test2_service: sleeping for 5 seconds" << endl);
return SLEEP;
case 3:
PRINT(cerr << "loom_test2_service: returning DONE" << endl);
return DONE;
default:
PRINT(cerr << "loom_test2_service: returning RESERVICE" << endl);
return RESERVICE;
}
}
Configure(loom_test2);
ConfigureFn(loom_test2)
{
RegisterAppService(loom_test2_init, loom_test2_service);
}

View File

@ -1,152 +0,0 @@
// Filename: test_diners.cxx
// Created by: cary (16Sep98)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
// A solution to the infamous dining philosophers, implemented using the
// threading abstraction. This program exercises thread creation and
// destruction, mutexes, and condition variables.
#include <pandabase.h>
#include <stdlib.h>
#include "ipc_thread.h"
#include "ipc_condition.h"
#ifdef WIN32_VC
static int last_rand = 0;
#endif /* __WIN32__ */
static mutex rand_mutex;
static int random_l(void)
{
mutex_lock l(rand_mutex);
int i = rand();
#ifdef WIN32_VC
last_rand = i;
#endif /* __WIN32__ */
return i;
}
static mutex print_mutex;
#define PRINTMSG(x) { mutex_lock l(print_mutex); x; }
// n philosophers sharing n chopsticks. Philosophers are poor folk and can't
// afford luxuries like 2 chopsticks per person.
#define N_DINERS 5
static mutex chopsticks[N_DINERS];
// At most n philosophers are allowed into the room, others would have to
// wait at the door. This restriction demonstrates the use of condition
// variables.
static mutex room_mutex;
static condition_variable room_condition(room_mutex);
static int room_occupancy = 0;
static class philosopher* phils[N_DINERS];
class philosopher : public thread {
private:
void run(void* arg) {
int id = *(int*)arg;
delete (int*)arg;
#ifdef WIN32_VC
rand_mutex.lock();
srand(last_rand);
rand_mutex.unlock();
#endif /* __WIN32__ */
int l = id;
int r = l+1;
if (r == N_DINERS)
r = 0;
if (l & 1) {
int t = l;
l = r;
r = t;
}
PRINTMSG(cerr << "Philosopher #" << id << " has entered the room."
<< endl);
int count = random_l() % 10 + 1;
while (--count) {
chopsticks[l].lock();
chopsticks[r].lock();
PRINTMSG(cerr << "Philosopher #" << id
<< " is eating spaghetti now." << endl);
thread::sleep(random_l()%2, random_l()%1000000000);
chopsticks[l].unlock();
chopsticks[r].unlock();
PRINTMSG(cerr << "Philosopher #" << id
<< " is pondering about life." << endl);
thread::sleep(random_l()%2, random_l()%1000000000);
}
room_mutex.lock();
--room_occupancy;
phils[id] = (philosopher*)0L;
room_mutex.unlock();
room_condition.signal();
PRINTMSG(cerr << "Philosopher #" << id << " has left the room ("
<< room_occupancy << " left)." << endl);
}
// the destructor of a class that inherits from thread should never be
// public (otherwise the thread object can be destroyed while the
// underlying thread is still running).
~philosopher(void) {}
inline void* make_arg(const int i) { return (void*)new int(i); }
public:
philosopher(const int id) : thread(make_arg(id)) {
start();
}
};
int main(int, char**)
{
int i;
room_mutex.lock();
for (i=0; i<N_DINERS; ++i)
phils[i] = new philosopher(i);
room_occupancy = N_DINERS;
while (1) {
while (room_occupancy == N_DINERS) {
PRINTMSG(cerr << "main thread about to block " << room_occupancy
<< endl);
room_condition.wait();
}
// hmm.. someone left the room.
room_mutex.unlock();
// sleep for a while and then create a new philosopher
PRINTMSG(cerr << "main thread sleep" << endl);
thread::sleep(1, 200000000);
PRINTMSG(cerr << "main thread wake up" << endl);
room_mutex.lock();
for (i=0; i<N_DINERS; ++i)
if (phils[i] == (philosopher*)0L)
break;
if (i == N_DINERS) {
PRINTMSG(cerr
<< "Contrary to what I was tolk, no one has left the room!!!"
<< endl);
PRINTMSG(cerr << "I give up!" << endl);
exit(1);
}
phils[i] = new philosopher(i);
++room_occupancy;
}
}

View File

@ -1,81 +0,0 @@
// Filename: test_file.cxx
// Created by: jason (05Sep00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include <pandabase.h>
#include "ipc_file.h"
#include <datagram.h>
#include <datagramIterator.h>
#include <notify.h>
#define _ERROR_TEST
int main(int argc, char* argv[])
{
//Test the writing capabilities
string test_file("test.out");
string test_data("Jason Michael Clark");
Datagram test_out; test_out.add_string(test_data);
datagram_file stream(test_file);
nout << "WRITE TEST" << endl;
nout << "Opening file for writing: " << test_file << endl;
if (!stream.open(file::FILE_WRITE)) nout << "Didn't open!" << endl;
nout << "Writing datagram with data: " << test_data << endl;
if (!stream.put_datagram(test_out)) nout << "Error in writing!" << endl;
nout << "Closing file: " << test_file << endl;
stream.close();
//Test the reading capabilites
Datagram test_in;
nout << "READ TEST" << endl;
nout << "Opening file for reading: " << test_file << endl;
if (!stream.open(file::FILE_READ)) nout << "Didn't open!" << endl;
if (!stream.get_datagram(test_in)) nout << "Error reading!" << endl;
DatagramIterator scan(test_in);
nout << "Read datagram with data: " << scan.get_string() << endl;
nout << "Closing file: " << test_file << endl;
stream.close();
#ifdef _ERROR_TEST
//Test error handling
Datagram test_error;
nout << "ERROR TEST" << endl;
nout << "Opening file for writing: " << test_file << endl;
stream.open(file::FILE_WRITE);
nout << "Trying to read datagram with data: " << endl;
stream.get_datagram(test_error);
nout << "Closing file: " << test_file << endl;
stream.close();
nout << "Opening file for reading: " << test_file << endl;
stream.open(file::FILE_READ);
nout << "Trying to write datagram with data: " << test_data << endl;
test_error.add_string(test_data);
stream.put_datagram(test_error);
nout << "Closing file: " << test_file << endl;
stream.close();
#endif
return 1;
}

View File

@ -1,94 +0,0 @@
// Filename: test_priority.cxx
// Created by: cary (16Sep98)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include <pandabase.h>
#include <stdlib.h>
#include <stdio.h>
#include "ipc_thread.h"
// test thread priorities
#if defined(__arm__) && defined(__atmos__)
#define flush ""
#endif /* __arm__ */
static void func(void*);
static int loop_iterations;
static mutex print_mutex;
#define PRINTMSG(x) { mutex_lock l(print_mutex); x << flush; }
int main(int argc, char** argv)
{
unsigned long s1, s2, n1, n2;
char buf[20];
if ((argc != 2) || (argv[1][0] == '-')) {
cerr << "Usage: " << argv[0] << " loop_iterations" << endl;
exit(1);
}
loop_iterations = atoi(argv[1]);
thread::get_time(s1, n1);
for (int i=0; i<loop_iterations; ++i);
thread::get_time(s2, n2);
if (n2 > n1) {
n2 -= n1;
s2 -= s1;
} else {
n2 = n2 + 1000000000 - n1;
s2 = s2 - 1 - s1;
}
sprintf(buf, "%d.%03d", s2, n2/1000000);
cout << argv[0] << ": doing " << loop_iterations
<< " loop itterations (approx " << buf << " seconds per loop)"
<< endl;
PRINTMSG(cout << "main: creating h1" << endl);
thread::create(func, (void*)"h1", thread::PRIORITY_HIGH);
PRINTMSG(cout << "main: creating m1" << endl);
thread::create(func, (void*)"m1", thread::PRIORITY_NORMAL);
PRINTMSG(cout << "main: creating l1" << endl);
thread::create(func, (void*)"l1", thread::PRIORITY_LOW);
PRINTMSG(cout << "main: creating h2" << endl);
thread::create(func, (void*)"h2", thread::PRIORITY_HIGH);
PRINTMSG(cout << "main: creating m2" << endl);
thread::create(func, (void*)"m2", thread::PRIORITY_NORMAL);
PRINTMSG(cout << "main: creating l2" << endl);
thread::self()->set_priority(thread::PRIORITY_LOW);
func((void*)"l2");
return 0;
}
static void func(void* arg)
{
char *name = (char *)arg;
while (1) {
PRINTMSG(cout << name << ": entering 1st compute-bound loop" << endl);
int i;
for (i=0; i<loop_iterations; ++i);
PRINTMSG(cout << name << ": left compute-bound loop; yielding" << endl);
thread::yield();
PRINTMSG(cout << name << ": entering 2nd compute-bound loop" << endl);
for (i=0; i<loop_iterations; ++i);
PRINTMSG(cout << name
<< ": left compute-bound loop; sleeping for 2 seconds" << endl);
thread::sleep(2);
}
}

View File

@ -1,106 +0,0 @@
// Filename: test_prodcons.cxx
// Created by: cary (16Sep98)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include <pandabase.h>
#include <stdlib.h>
#include "ipc_thread.h"
#include "ipc_condition.h"
#include "ipc_mutex.h"
// test condition variables and timed waits. makes 2 'producer' threads and
// 3 'consumer' threads
static void producer(void*);
static void consumer(void*);
mutex m;
condition_variable full(m);
condition_variable empty(m);
bool empty_flag = true;
const char* message;
static const char* msgs[] = { "wolf", "fox", "hyena", "dingo" };
int main(int, char**)
{
cerr << "main: creating producer1" << endl;
thread::create(producer, (void*)"producer1");
cerr << "main: creating producer2" << endl;
thread::create(producer, (void*)"producer2");
cerr << "main: creating consumer1" << endl;
thread::create(consumer, (void*)"consumer1");
cerr << "main: creating consumer2" << endl;
thread::create(consumer, (void*)"consumer2");
cerr << "main: creating consumer3" << endl;
consumer((void*)"consumer3");
return 0;
}
static int random_l(void)
{
static mutex rand_mutex;
mutex_lock l(rand_mutex);
int i = rand();
return i;
}
static void consumer(void* arg)
{
char *name = (char *)arg;
unsigned long s, n;
while (1) {
{
mutex_lock l(m);
thread::get_time(s, n, 0, 500000000); // 1/2 second from now
while (empty_flag) {
cerr << name << ": waiting for message" << endl;
if (!full.timedwait(s, n)) {
cerr << name << ": timed out, trying again" << endl;
thread::get_time(s, n, 0, 500000000);
} else if (empty_flag)
cerr << name << ": woken but message already consumed" << endl;
}
cerr << name << ": got message: '" << message << "'" << endl;
empty_flag = true;
empty.signal();
}
thread::sleep(random_l() % 2, 1000000 * (random_l() % 1000));
}
}
static void producer(void* arg)
{
char *name = (char *)arg;
while (1) {
{
mutex_lock l(m);
while (!empty_flag) {
cerr << name << ": having to wait for consumer" << endl;
empty.wait();
}
message = msgs[random_l() % 4];
empty_flag = false;
full.signal();
cerr << name << ": put message: '" << message << "'" << endl;
}
thread::sleep(random_l() % 2, 1000000 * (random_l() % 500) + 500);
}
}

View File

@ -1,103 +0,0 @@
// Filename: test_thread.cxx
// Created by:
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include <pandabase.h>
#include <stdlib.h>
#include "ipc_thread.h"
#include "ipc_condition.h"
static mutex print_mutex;
static mutex m;
static condition_variable cv(m);
class CTestThread : public thread
{
private:
void run(void *arg)
{
cout << "Hey main. This is " << (char *) arg << ". Wake the hell up." << endl;
cout.flush();
cv.signal();
}
public:
CTestThread(char *name) : thread(name)
{
cout << name << " LIVES!." << endl;
cout.flush();
start();
}
~CTestThread(void) {}
};
class CTestThread2 : public thread
{
private:
void run(void *arg)
{
cout << "Oh- so NOW you need me." << endl;
cout.flush();
cv.wait();
cv.signal();
cout << "bastid." << endl;
cout.flush();
}
public:
CTestThread2(char *name) : thread(name)
{
cout << name << " LIVES!." << endl;
cout.flush();
start();
}
~CTestThread2(void) {}
};
int main(int, char **)
{
CTestThread *test_thread = new CTestThread("test_thread");
CTestThread2 *test_thread2 = new CTestThread2("test_thread2");
cout << "My name is main, and i'm going to go to sleep." << endl;
cout.flush();
cv.wait();
cout << "I hate you test_thread." << endl;
cout.flush();
cv.signal();
cv.wait();
cout << "I hate you test_thread2." << endl;
cout.flush();
return 0;
}

View File

@ -1,57 +0,0 @@
// Filename: test_threaddata.cxx
// Created by: cary (16Sep98)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include <pandabase.h>
#include "ipc_thread.h"
// test a derived class from thread with thread specific data, as well as the
// joining mechanism.
class thread_with_data : public thread {
private:
int _my_thread_id_plus_two;
void* run_undetached(void* ptr) {
int arg = *(int*)ptr;
delete (int*)ptr;
cerr << "Thread: run invoked with arg " << arg << endl;
cerr << "Thread: my id is " << get_id() << endl;
cerr << "Thread: my private data (id plus 2) is "
<< _my_thread_id_plus_two << endl;
int* rv = new int(_my_thread_id_plus_two + 1);
cerr << "Thread: returning " << *rv << endl;
return (void*)rv;
}
~thread_with_data(void) {}
static void* make_arg(const int i) { return (void*)new int(i); }
public:
thread_with_data(void) : thread(make_arg(5)) {
_my_thread_id_plus_two = get_id() + 2;
start_undetached();
}
};
int main(int, char**)
{
thread_with_data *t = new thread_with_data;
cerr << "main: joining" << endl;
int* rv;
t->join((void**)&rv);
cerr << "main: joined - got return value " << *rv << endl;
delete rv;
return 0;
}

View File

@ -145,7 +145,7 @@ request_load(const Filename &filename, const string &event_name) {
}
// We need to grab the lock in order to signal the condition variable
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
_lock.lock();
#endif
@ -163,7 +163,7 @@ request_load(const Filename &filename, const string &event_name) {
tok = new LoaderToken(_next_token++, filename, event_name);
_token_board->_waiting.push_back(tok);
#ifdef HAVE_IPC
#ifdef OLD_HAVE_IPC
_request_cond->signal();
_lock.unlock();
#endif