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