Panda3D

clientBase.cxx
Go to the documentation of this file.
1 /**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file clientBase.cxx
10 * @author jason
11 * @date 2000-08-04
12 */
13
14 #include "clientBase.h"
15 #include "config_device.h"
16
17 TypeHandle ClientBase::_type_handle;
18
19 /**
20 *
21 */
22 ClientBase::
23 ClientBase() {
24 _forked = false;
25 _last_poll_time = 0.0f;
26 _last_poll_frame = 0;
27 _cs = CS_default;
28
29 #ifdef OLD_HAVE_IPC
30 _client_thread = nullptr;
31 _shutdown = false;
32 #endif
33 }
34
35
36 /**
37 *
38 */
39 ClientBase::
40 ~ClientBase() {
41 // We have to disconnect all of our devices before destructing.
42 Devices::iterator di;
43 Devices devices_copy = _devices;
44 for (di = devices_copy.begin(); di != devices_copy.end(); ++di) {
45 DevicesByName &dbn = (*di).second;
46 DevicesByName::iterator dbni;
47 for (dbni = dbn.begin(); dbni != dbn.end(); ++dbni) {
48 ClientDevice *device = (*dbni).second;
49 device->disconnect();
50 }
51 }
52
53 #ifdef OLD_HAVE_IPC
54 if (_forked) {
55 _shutdown = true;
56
57 // Join the loader thread - calling process blocks until the loader thread
58 // returns.
59 void *ret;
60 _client_thread->join(&ret);
61 }
62 #endif
63 }
64
65 /**
66 * Forks a separate thread to do all the polling of connected devices. The
67 * forked thread will poll after every poll_time seconds has elapsed. Returns
68 * true if the fork was successful, or false otherwise (for instance, because
69 * we were already forked, or because asynchronous threads are disabled).
70 */
71 bool ClientBase::
72 fork_asynchronous_thread(double poll_time) {
73 #ifdef OLD_HAVE_IPC
74 if (_forked) {
75 device_cat.error()
76 << "Attempt to fork client thread twice.\n";
77 return false;
78 }
79
80 if (asynchronous_clients) {
81 _sleep_time = (int)(1000000 * poll_time);
82
83 _client_thread = thread::create(&st_callback, this);
84 _forked = true;
85 if (device_cat.is_debug()) {
86 device_cat.debug()
87 << "fork_asynchronous_thread() - forking client thread"
88 << std::endl;
89 }
90 return true;
91 }
92 #endif
93
94 return false;
95 }
96
97 /**
98 * Returns a ClientDevice pointer that corresponds to the named device of the
99 * indicated device type. The device_type should be one of
100 * ClientTrackerDevice, ClientAnalogDevice, etc.; the device_name is
101 * implementation defined.
102 *
103 * Normally, the user does not need to call this function directly; it is
104 * called automatically by creating a TrackerNode or AnalogNode or some such
105 * data graph node.
106 *
107 * The return value is the pointer to the created device (which might be the
108 * same pointer returned by a previous call to this function with the same
109 * parameters). When the pointer destructs (i.e. its reference count reaches
110 * zero) it will automatically be disconnected.
111 *
112 * If the named device does not exist or cannot be connected for some reason,
113 * NULL is returned.
114 */
115 PT(ClientDevice) ClientBase::
116 get_device(TypeHandle device_type, const std::string &device_name) {
117 DevicesByName &dbn = _devices[device_type];
118
119 DevicesByName::iterator dbni;
120 dbni = dbn.find(device_name);
121 if (dbni != dbn.end()) {
122 // This device was previously connected. Return it again.
123 return (*dbni).second;
124 }
125
126 // We need to create a new device for this name.
127 PT(ClientDevice) device = make_device(device_type, device_name);
128
129 if (device != nullptr) {
130 dbn.insert(DevicesByName::value_type(device_name, device));
131 }
132
133 return device;
134 }
135
136 /**
137 * Removes the device, which is presumably about to destruct, from the list of
138 * connected devices, and frees any data required to support it. This device
139 * will no longer receive automatic updates with each poll.
140 *
141 * The return value is true if the device was disconnected, or false if it was
142 * unknown (e.g. it was disconnected previously).
143 */
144 bool ClientBase::
145 disconnect_device(TypeHandle device_type, const std::string &device_name,
146 ClientDevice *device) {
147 DevicesByName &dbn = _devices[device_type];
148
149 DevicesByName::iterator dbni;
150 dbni = dbn.find(device_name);
151 if (dbni != dbn.end()) {
152 if ((*dbni).second == device) {
153 // We found it!
154 dbn.erase(dbni);
155 return true;
156 }
157 }
158
159 // The device was unknown.
160 return false;
161 }
162
163 /**
164 * Implements the polling and updating of connected devices, if the ClientBase
165 * requires this. This may be called in a sub-thread if
166 * fork_asynchronous_thread() was called; otherwise, it will be called once
167 * per frame.
168 */
169 void ClientBase::
170 do_poll() {
171 ClockObject *global_clock = ClockObject::get_global_clock();
172 _last_poll_frame = global_clock->get_frame_count();
173 _last_poll_time = global_clock->get_frame_time();
174 }
175
176 #ifdef OLD_HAVE_IPC
177 /**
178 * Call back function for thread (if thread has been spawned). A call back
179 * function must be static, so this merely calls the non-static member
180 * callback In addition, the function has a void* return type even though we
181 * don't actually return anything. This is necessary because ipc assumes a
182 * function that does not return anything indicates that the associated thread
183 * should be created as unjoinable (detached).
184 */
185 void *ClientBase::
186 st_callback(void *arg) {
187 nassertr(arg != nullptr, nullptr);
188 ((ClientBase *)arg)->callback();
189 return nullptr;
190 }
191
192 /**
193 * This is the main body of the sub-thread. It sleeps a certain time and then
194 * polls all devices currently being watched
195 */
196 void ClientBase::
197 callback() {
198 while (true) {
199 if (_shutdown) {
200 break;
201 }
202 do_poll();
203 ipc_traits::sleep(0, _sleep_time);
204 }
205 }
206 #endif // OLD_HAVE_IPC
ClientBase
An abstract base class for a family of client device interfaces–including trackers,...
Definition: clientBase.h:43
ClientBase::fork_asynchronous_thread
bool fork_asynchronous_thread(double poll_time)
Forks a separate thread to do all the polling of connected devices.
Definition: clientBase.cxx:72
ClientDevice
Any of a number of different devices that might be attached to a ClientBase, including trackers,...
Definition: clientDevice.h:27
ClientDevice::disconnect
void disconnect()
Disconnects the ClientDevice from its ClientBase object.
Definition: clientDevice.cxx:61
ClockObject
A ClockObject keeps track of elapsed real time and discrete time.
Definition: clockObject.h:58
ClockObject::get_frame_time
get_frame_time
Returns the time in seconds as of the last time tick() was called (typically, this will be as of the ...
Definition: clockObject.h:91
ClockObject::get_frame_count
get_frame_count
Returns the number of times tick() has been called since the ClockObject was created,...
Definition: clockObject.h:94
ClockObject::get_global_clock
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Definition: clockObject.I:215
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
PT
PT(ClientDevice) ClientBase
Returns a ClientDevice pointer that corresponds to the named device of the indicated device type.
Definition: clientBase.cxx:115
clientBase.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
config_device.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.