first pass at new ipc
This commit is contained in:
parent
d757224ff8
commit
58b5397d87
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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"
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
ConfigureDef(config_express);
|
||||
NotifyCategoryDef(express, "");
|
||||
NotifyCategoryDef(ipc, "");
|
||||
|
||||
extern void init_system_type_handles();
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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 ©) {
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Mutex::Copy Assignment Operator
|
||||
// Access: Private
|
||||
// Description: Do not attempt to copy mutexes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void Mutex::
|
||||
operator = (const Mutex ©) {
|
||||
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();
|
||||
}
|
||||
|
|
@ -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"
|
||||
|
|
@ -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 ©);
|
||||
INLINE void operator = (const Mutex ©);
|
||||
|
||||
public:
|
||||
INLINE void lock();
|
||||
INLINE void release();
|
||||
|
||||
private:
|
||||
MutexImpl _impl;
|
||||
};
|
||||
|
||||
#include "mutex.I"
|
||||
|
||||
#endif
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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 ©) {
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexHolder::Copy Assignment Operator
|
||||
// Access: Private
|
||||
// Description: Do not attempt to copy MutexHolders.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void MutexHolder::
|
||||
operator = (const MutexHolder ©) {
|
||||
nassertv(false);
|
||||
}
|
||||
|
|
@ -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"
|
||||
|
|
@ -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 ©);
|
||||
INLINE void operator = (const MutexHolder ©);
|
||||
|
||||
private:
|
||||
#ifdef HAVE_IPC
|
||||
Mutex *_mutex;
|
||||
#endif
|
||||
};
|
||||
|
||||
#include "mutexHolder.I"
|
||||
|
||||
#endif
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 ©) : _impl(this) {
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Thread::Copy Assignment Operator
|
||||
// Access: Private
|
||||
// Description: Do not attempt to copy threads.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void Thread::
|
||||
operator = (const Thread ©) {
|
||||
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);
|
||||
}
|
||||
|
|
@ -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() {
|
||||
}
|
||||
|
|
@ -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 ©);
|
||||
INLINE void operator = (const Thread ©);
|
||||
|
||||
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
|
||||
|
|
@ -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) {
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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));
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
|
||||
#include "ipc.cxx"
|
||||
#include "ipc_traits.cxx"
|
||||
|
||||
|
|
@ -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__ */
|
||||
|
|
@ -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__ */
|
||||
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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__ */
|
||||
|
|
@ -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__ */
|
||||
|
|
@ -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__ */
|
||||
|
|
@ -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,
|
||||
¶m));
|
||||
#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__ */
|
||||
|
|
@ -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__
|
||||
|
|
@ -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__ */
|
||||
|
|
@ -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__ */
|
||||
|
|
@ -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__ */
|
||||
|
|
@ -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 */
|
||||
|
||||
|
||||
|
|
@ -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__ */
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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__ */
|
||||
|
|
@ -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__ */
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue