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