Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/device/clientBase.cxx

Go to the documentation of this file.
00001 // Filename: clientBase.cxx
00002 // Created by:  jason (04Aug00)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 
00020 #include "clientBase.h"
00021 #include "config_device.h"
00022 
00023 TypeHandle ClientBase::_type_handle;
00024 
00025 ////////////////////////////////////////////////////////////////////
00026 //     Function: ClientBase::constructor
00027 //       Access: Protected
00028 //  Description:
00029 ////////////////////////////////////////////////////////////////////
00030 ClientBase::
00031 ClientBase() {
00032   _forked = false;
00033   _last_poll_time = 0.0f;
00034   _last_poll_frame = 0;
00035   _cs = CS_default;
00036 
00037 #ifdef OLD_HAVE_IPC
00038   _client_thread = (thread *)NULL;
00039   _shutdown = false;
00040 #endif
00041 }
00042 
00043 
00044 ////////////////////////////////////////////////////////////////////
00045 //     Function: ClientBase::destructor
00046 //       Access: Public
00047 //  Description:
00048 ////////////////////////////////////////////////////////////////////
00049 ClientBase::
00050 ~ClientBase() {
00051   // We have to disconnect all of our devices before destructing.
00052   Devices::iterator di;
00053   Devices devices_copy = _devices;
00054   for (di = devices_copy.begin(); di != devices_copy.end(); ++di) {
00055     DevicesByName &dbn = (*di).second;
00056     DevicesByName::iterator dbni;
00057     for (dbni = dbn.begin(); dbni != dbn.end(); ++dbni) {
00058       ClientDevice *device = (*dbni).second;
00059       device->disconnect();
00060     }
00061   }
00062 
00063 #ifdef OLD_HAVE_IPC
00064   if (_forked) {
00065     _shutdown = true;
00066 
00067     // Join the loader thread - calling process blocks until the loader
00068     // thread returns.
00069     void *ret;
00070     _client_thread->join(&ret);
00071   }
00072 #endif
00073 }
00074 
00075 ////////////////////////////////////////////////////////////////////
00076 //     Function: ClientBase::fork_asynchronous_thread
00077 //       Access: Public
00078 //  Description: Forks a separate thread to do all the polling of
00079 //               connected devices.  The forked thread will poll after
00080 //               every poll_time seconds has elapsed.  Returns true if
00081 //               the fork was successful, or false otherwise (for
00082 //               instance, because we were already forked, or because
00083 //               asynchronous threads are disabled).
00084 ////////////////////////////////////////////////////////////////////
00085 bool ClientBase::
00086 fork_asynchronous_thread(double poll_time) {
00087 #ifdef OLD_HAVE_IPC
00088   if (_forked) {
00089     device_cat.error()
00090       << "Attempt to fork client thread twice.\n";
00091     return false;
00092   }
00093 
00094   if (asynchronous_clients) {
00095     _sleep_time = (int)(1000000 * poll_time);
00096 
00097     _client_thread = thread::create(&st_callback, this);
00098     _forked = true;
00099     if (device_cat.is_debug()) {
00100       device_cat.debug()
00101         << "fork_asynchronous_thread() - forking client thread"
00102         << endl;
00103     }
00104     return true;
00105   }
00106 #endif
00107 
00108   return false;
00109 }
00110 
00111 ////////////////////////////////////////////////////////////////////
00112 //     Function: ClientBase::get_device
00113 //       Access: Public
00114 //  Description: Returns a ClientDevice pointer that corresponds to
00115 //               the named device of the indicated device type.  The
00116 //               device_type should be one of ClientTrackerDevice,
00117 //               ClientAnalogDevice, etc.; the device_name is
00118 //               implementation defined.
00119 //
00120 //               Normally, the user does not need to call this
00121 //               function directly; it is called automatically by
00122 //               creating a TrackerNode or AnalogNode or some such
00123 //               data graph node.
00124 //
00125 //               The return value is the pointer to the created device
00126 //               (which might be the same pointer returned by a
00127 //               previous call to this function with the same
00128 //               parameters).  When the pointer destructs (i.e. its
00129 //               reference count reaches zero) it will automatically
00130 //               be disconnected.
00131 //
00132 //               If the named device does not exist or cannot be
00133 //               connected for some reason, NULL is returned.
00134 ////////////////////////////////////////////////////////////////////
00135 PT(ClientDevice) ClientBase::
00136 get_device(TypeHandle device_type, const string &device_name) {
00137   DevicesByName &dbn = _devices[device_type];
00138 
00139   DevicesByName::iterator dbni;
00140   dbni = dbn.find(device_name);
00141   if (dbni != dbn.end()) {
00142     // This device was previously connected.  Return it again.
00143     return (*dbni).second;
00144   }
00145 
00146   // We need to create a new device for this name.
00147   PT(ClientDevice) device = make_device(device_type, device_name);
00148 
00149   if (device != (ClientDevice *)NULL) {
00150     dbn.insert(DevicesByName::value_type(device_name, device));
00151     device->_is_connected = true;
00152   }
00153 
00154   return device;
00155 }
00156 
00157 ////////////////////////////////////////////////////////////////////
00158 //     Function: ClientBase::disconnect_device
00159 //       Access: Protected, Virtual
00160 //  Description: Removes the device, which is presumably about to
00161 //               destruct, from the list of connected devices, and
00162 //               frees any data required to support it.  This device
00163 //               will no longer receive automatic updates with each
00164 //               poll.
00165 //
00166 //               The return value is true if the device was
00167 //               disconnected, or false if it was unknown (e.g. it was
00168 //               disconnected previously).
00169 ////////////////////////////////////////////////////////////////////
00170 bool ClientBase::
00171 disconnect_device(TypeHandle device_type, const string &device_name,
00172                   ClientDevice *device) {
00173   DevicesByName &dbn = _devices[device_type];
00174 
00175   DevicesByName::iterator dbni;
00176   dbni = dbn.find(device_name);
00177   if (dbni != dbn.end()) {
00178     if ((*dbni).second == device) {
00179       // We found it!
00180       dbn.erase(dbni);
00181       return true;
00182     }
00183   }
00184 
00185   // The device was unknown.
00186   return false;
00187 }
00188 
00189 ////////////////////////////////////////////////////////////////////
00190 //     Function: ClientBase::do_poll
00191 //       Access: Protected, Virtual
00192 //  Description: Implements the polling and updating of connected
00193 //               devices, if the ClientBase requires this.  This may
00194 //               be called in a sub-thread if
00195 //               fork_asynchronous_thread() was called; otherwise, it
00196 //               will be called once per frame.
00197 ////////////////////////////////////////////////////////////////////
00198 void ClientBase::
00199 do_poll() {
00200   ClockObject *global_clock = ClockObject::get_global_clock();
00201   _last_poll_frame = global_clock->get_frame_count();
00202   _last_poll_time = global_clock->get_frame_time();
00203 }
00204 
00205 #ifdef OLD_HAVE_IPC
00206 ////////////////////////////////////////////////////////////////////
00207 //     Function: ClientBase::st_callback
00208 //       Access: Private, static
00209 //  Description: Call back function for thread (if thread has been
00210 //               spawned).  A call back function must be static, so
00211 //               this merely calls the non-static member callback In
00212 //               addition, the function has a void* return type even
00213 //               though we don't actually return anything.  This is
00214 //               necessary because ipc assumes a function that does
00215 //               not return anything indicates that the associated
00216 //               thread should  be created as unjoinable (detached).
00217 ////////////////////////////////////////////////////////////////////
00218 void *ClientBase::
00219 st_callback(void *arg) {
00220   nassertr(arg != NULL, NULL);
00221   ((ClientBase *)arg)->callback();
00222   return NULL;
00223 }
00224 
00225 ////////////////////////////////////////////////////////////////////
00226 //     Function: ClientBase::callback
00227 //       Access: Private
00228 //  Description: This is the main body of the sub-thread.  It sleeps
00229 //               a certain time and then polls all devices currently
00230 //               being watched
00231 ////////////////////////////////////////////////////////////////////
00232 void ClientBase::
00233 callback() {
00234   while (true) {
00235     if (_shutdown) {
00236       break;
00237     }
00238     do_poll();
00239     ipc_traits::sleep(0, _sleep_time);
00240   }
00241 }
00242 #endif // OLD_HAVE_IPC

Generated on Fri May 2 00:36:09 2003 for Panda by doxygen1.3