P3D_check_request(timeout)

This commit is contained in:
David Rose 2009-08-26 19:42:36 +00:00
parent 35bf03caf1
commit a4fcdbe5b9
7 changed files with 180 additions and 30 deletions

View File

@ -44,12 +44,21 @@ class panda3d(package):
# automatically be included as well, and we end up with a pretty # automatically be included as well, and we end up with a pretty
# complete list that way. # complete list that way.
module('direct.directbase.DirectStart', module('direct.directbase.DirectStart',
'direct.actor.*',
'direct.controls.*',
'direct.directdevices.*',
'direct.directnotify.*',
'direct.directtools.*',
'direct.directutil.*',
'direct.distributed.*',
'direct.fsm.*',
'direct.gui.*',
'direct.interval.*',
'direct.particles.*',
'direct.showbase.*', 'direct.showbase.*',
'direct.actor.Actor', 'direct.showutil.*',
'direct.fsm.FSM', 'direct.stdpy.*')
'direct.interval.IntervalGlobal',
'direct.particles.ParticleEffect',
'direct.directutil.Mopath')
# Exclude these GUI toolkits; they're big, and many applications don't # Exclude these GUI toolkits; they're big, and many applications don't
# use them. We define them as separate, optional packages, below. # use them. We define them as separate, optional packages, below.

View File

@ -404,7 +404,8 @@ check_request() {
// Function: P3DInstanceManager::wait_request // Function: P3DInstanceManager::wait_request
// Access: Public // Access: Public
// Description: Does not return until a request is pending on some // Description: Does not return until a request is pending on some
// instance, or until no instances remain. Use // instance, or until no instances remain, or until the
// indicated time in seconds has elapsed. Use
// check_request to retrieve the pending request. Due // check_request to retrieve the pending request. Due
// to the possibility of race conditions, it is possible // to the possibility of race conditions, it is possible
// for this function to return when there is in fact no // for this function to return when there is in fact no
@ -412,9 +413,60 @@ check_request() {
// the request first). // the request first).
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void P3DInstanceManager:: void P3DInstanceManager::
wait_request() { wait_request(double timeout) {
#ifdef _WIN32
int stop_tick = int(GetTickCount() + timeout * 1000.0);
#else
struct timeval stop_time;
gettimeofday(&stop_time, NULL);
int seconds = (int)floor(timeout);
stop_time.tv_sec += seconds;
stop_time.tv_usec += (int)((timeout - seconds) * 1000.0);
if (stop_time.tv_usec > 1000) {
stop_time.tv_usec -= 1000;
++stop_time.tv_sec;
}
#endif
_request_ready.acquire(); _request_ready.acquire();
if (check_request() != (P3DInstance *)NULL) {
_request_ready.release();
return;
}
if (_instances.empty()) {
_request_ready.release();
return;
}
// No pending requests; go to sleep.
_request_ready.wait(timeout);
while (true) { while (true) {
#ifdef _WIN32
int remaining_ticks = stop_tick - GetTickCount();
if (remaining_ticks <= 0) {
break;
}
timeout = remaining_ticks * 0.001;
#else
struct timeval now;
gettimeofday(&now, NULL);
struct timeval remaining;
remaining.tv_sec = stop_time.tv_sec - now.tv_sec;
remaining.tv_usec = stop_time.tv_usec - now.tv_usec;
if (remaining.tv_usec < 0) {
remaining.tv_usec += 1000;
--remaining.tv_sec;
}
if (remaining.tv_sec < 0) {
break;
}
timeout = remaining.tv_sec + remaining.tv_usec * 0.001;
#endif
if (check_request() != (P3DInstance *)NULL) { if (check_request() != (P3DInstance *)NULL) {
_request_ready.release(); _request_ready.release();
return; return;
@ -425,7 +477,7 @@ wait_request() {
} }
// No pending requests; go to sleep. // No pending requests; go to sleep.
_request_ready.wait(); _request_ready.wait(timeout);
} }
_request_ready.release(); _request_ready.release();
} }

View File

@ -73,7 +73,7 @@ public:
P3DInstance *validate_instance(P3D_instance *instance); P3DInstance *validate_instance(P3D_instance *instance);
P3DInstance *check_request(); P3DInstance *check_request();
void wait_request(); void wait_request(double timeout);
P3DHost *get_host(const string &host_url); P3DHost *get_host(const string &host_url);

View File

@ -25,6 +25,7 @@
#include "p3dStringObject.h" #include "p3dStringObject.h"
#include <assert.h> #include <assert.h>
#include <math.h>
// Use a simple lock to protect the C-style API functions in this // Use a simple lock to protect the C-style API functions in this
// module from parallel access by multiple threads in the host. // module from parallel access by multiple threads in the host.
@ -405,21 +406,65 @@ P3D_instance_get_request(P3D_instance *instance) {
} }
P3D_instance * P3D_instance *
P3D_check_request(bool wait) { P3D_check_request(double timeout) {
assert(P3DInstanceManager::get_global_ptr()->is_initialized()); assert(P3DInstanceManager::get_global_ptr()->is_initialized());
ACQUIRE_LOCK(_api_lock); ACQUIRE_LOCK(_api_lock);
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
P3D_instance *inst = inst_mgr->check_request(); P3D_instance *inst = inst_mgr->check_request();
if (inst != NULL || !wait) { if (inst != NULL || timeout <= 0.0) {
RELEASE_LOCK(_api_lock); RELEASE_LOCK(_api_lock);
return inst; return inst;
} }
#ifdef _WIN32
int stop_tick = int(GetTickCount() + timeout * 1000.0);
#else
struct timeval stop_time;
gettimeofday(&stop_time, NULL);
int seconds = (int)floor(timeout);
stop_time.tv_sec += seconds;
stop_time.tv_usec += (int)((timeout - seconds) * 1000.0);
if (stop_time.tv_usec > 1000) {
stop_time.tv_usec -= 1000;
++stop_time.tv_sec;
}
#endif
// Now we have to block until a request is available. // Now we have to block until a request is available.
RELEASE_LOCK(_api_lock);
inst_mgr->wait_request(timeout);
ACQUIRE_LOCK(_api_lock);
inst = inst_mgr->check_request();
while (inst == NULL && inst_mgr->get_num_instances() != 0) { while (inst == NULL && inst_mgr->get_num_instances() != 0) {
#ifdef _WIN32
int remaining_ticks = stop_tick - GetTickCount();
if (remaining_ticks <= 0) {
break;
}
timeout = remaining_ticks * 0.001;
#else
struct timeval now;
gettimeofday(&now, NULL);
struct timeval remaining;
remaining.tv_sec = stop_time.tv_sec - now.tv_sec;
remaining.tv_usec = stop_time.tv_usec - now.tv_usec;
if (remaining.tv_usec < 0) {
remaining.tv_usec += 1000;
--remaining.tv_sec;
}
if (remaining.tv_sec < 0) {
break;
}
timeout = remaining.tv_sec + remaining.tv_usec * 0.001;
#endif
RELEASE_LOCK(_api_lock); RELEASE_LOCK(_api_lock);
inst_mgr->wait_request(); inst_mgr->wait_request(timeout);
ACQUIRE_LOCK(_api_lock); ACQUIRE_LOCK(_api_lock);
inst = inst_mgr->check_request(); inst = inst_mgr->check_request();
} }

View File

@ -738,10 +738,9 @@ P3D_instance_get_request_func(P3D_instance *instance);
If any open instance has a pending request, this function will If any open instance has a pending request, this function will
return a pointer to one of them (which you may then pass to return a pointer to one of them (which you may then pass to
P3D_instance_get_request_func). If no instances have a pending P3D_instance_get_request_func). If no instances have a pending
request, this function will return NULL. If wait is true, this request, this function will return NULL. This function will not
function will never return NULL unless there are no instances open; return until at least timeout seconds have elapsed, or a request is
instead, it will wait indefinitely until there is a request available, whichever comes first.
available.
Note that, due to race conditions, it is possible for this function Note that, due to race conditions, it is possible for this function
to return a P3D_instance that does not in fact have any requests to return a P3D_instance that does not in fact have any requests
@ -749,7 +748,7 @@ P3D_instance_get_request_func(P3D_instance *instance);
should always verify that the return value of should always verify that the return value of
P3D_instance_get_request() is not NULL. */ P3D_instance_get_request() is not NULL. */
typedef P3D_instance * typedef P3D_instance *
P3D_check_request_func(bool wait); P3D_check_request_func(double timeout);
/* A request retrieved by P3D_instance_get_request() should eventually /* A request retrieved by P3D_instance_get_request() should eventually
be passed here, after it has been handled, to deallocate its be passed here, after it has been handled, to deallocate its

View File

@ -36,6 +36,9 @@
#endif #endif
// The amount of time in seconds to wait for new messages.
static const double wait_cycle = 0.2;
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: Panda3D::Constructor // Function: Panda3D::Constructor
// Access: Public // Access: Public
@ -61,7 +64,7 @@ run(int argc, char *argv[]) {
// We prefix a "+" sign to tell gnu getopt not to parse options // We prefix a "+" sign to tell gnu getopt not to parse options
// following the first not-option parameter. (These will be passed // following the first not-option parameter. (These will be passed
// into the sub-process.) // into the sub-process.)
const char *optstr = "+mu:p:ft:s:o:l:h"; const char *optstr = "+mu:p:fw:t:s:o:l:h";
bool allow_multiple = false; bool allow_multiple = false;
string download_url = PANDA_PACKAGE_HOST_URL; string download_url = PANDA_PACKAGE_HOST_URL;
@ -92,7 +95,7 @@ run(int argc, char *argv[]) {
verify_contents = true; verify_contents = true;
break; break;
case 't': case 'w':
if (strcmp(optarg, "toplevel") == 0) { if (strcmp(optarg, "toplevel") == 0) {
window_type = P3D_WT_toplevel; window_type = P3D_WT_toplevel;
} else if (strcmp(optarg, "embedded") == 0) { } else if (strcmp(optarg, "embedded") == 0) {
@ -102,7 +105,14 @@ run(int argc, char *argv[]) {
} else if (strcmp(optarg, "hidden") == 0) { } else if (strcmp(optarg, "hidden") == 0) {
window_type = P3D_WT_hidden; window_type = P3D_WT_hidden;
} else { } else {
cerr << "Invalid value for -t: " << optarg << "\n"; cerr << "Invalid value for -w: " << optarg << "\n";
return 1;
}
break;
case 't':
if (!parse_token(optarg)) {
cerr << "Web tokens (-t) must be of the form token=value: " << optarg << "\n";
return 1; return 1;
} }
break; break;
@ -248,13 +258,13 @@ run(int argc, char *argv[]) {
DispatchMessage(&msg); DispatchMessage(&msg);
// Check for new requests from the Panda3D plugin. // Check for new requests from the Panda3D plugin.
P3D_instance *inst = P3D_check_request(false); P3D_instance *inst = P3D_check_request(wait_cycle);
while (inst != (P3D_instance *)NULL) { while (inst != (P3D_instance *)NULL) {
P3D_request *request = P3D_instance_get_request(inst); P3D_request *request = P3D_instance_get_request(inst);
if (request != (P3D_request *)NULL) { if (request != (P3D_request *)NULL) {
handle_request(request); handle_request(request);
} }
inst = P3D_check_request(false); inst = P3D_check_request(wait_cycle);
} }
while (!_url_getters.empty() && while (!_url_getters.empty() &&
@ -276,7 +286,7 @@ run(int argc, char *argv[]) {
// Not an embedded window, so we don't have our own window to // Not an embedded window, so we don't have our own window to
// generate Windows events. Instead, just wait for requests. // generate Windows events. Instead, just wait for requests.
while (!_instances.empty()) { while (!_instances.empty()) {
P3D_instance *inst = P3D_check_request(false); P3D_instance *inst = P3D_check_request(wait_cycle);
if (inst != (P3D_instance *)NULL) { if (inst != (P3D_instance *)NULL) {
P3D_request *request = P3D_instance_get_request(inst); P3D_request *request = P3D_instance_get_request(inst);
if (request != (P3D_request *)NULL) { if (request != (P3D_request *)NULL) {
@ -294,7 +304,7 @@ run(int argc, char *argv[]) {
EventLoopRef main_loop = GetMainEventLoop(); EventLoopRef main_loop = GetMainEventLoop();
EventLoopTimerUPP timer_upp = NewEventLoopTimerUPP(st_timer_callback); EventLoopTimerUPP timer_upp = NewEventLoopTimerUPP(st_timer_callback);
EventLoopTimerRef timer; EventLoopTimerRef timer;
EventTimerInterval interval = 200 * kEventDurationMillisecond; EventTimerInterval interval = wait_cycle * kEventDurationSecond;
InstallEventLoopTimer(main_loop, interval, interval, InstallEventLoopTimer(main_loop, interval, interval,
timer_upp, this, &timer); timer_upp, this, &timer);
RunApplicationEventLoop(); RunApplicationEventLoop();
@ -310,7 +320,7 @@ run(int argc, char *argv[]) {
// Now wait while we process pending requests. // Now wait while we process pending requests.
while (!_instances.empty()) { while (!_instances.empty()) {
P3D_instance *inst = P3D_check_request(false); P3D_instance *inst = P3D_check_request(wait_cycle);
if (inst != (P3D_instance *)NULL) { if (inst != (P3D_instance *)NULL) {
P3D_request *request = P3D_instance_get_request(inst); P3D_request *request = P3D_instance_get_request(inst);
if (request != (P3D_request *)NULL) { if (request != (P3D_request *)NULL) {
@ -647,7 +657,7 @@ create_instance(const string &p3d, P3D_window_type window_type,
} }
// Build up the token list. // Build up the token list.
pvector<P3D_token> tokens; Tokens tokens = _tokens;
P3D_token token; P3D_token token;
string log_basename; string log_basename;
@ -745,7 +755,11 @@ usage() {
<< " time, but additional arguments may not be passed to any of the\n" << " time, but additional arguments may not be passed to any of the\n"
<< " applictions.\n\n" << " applictions.\n\n"
<< " -t [toplevel|embedded|fullscreen|hidden]\n" << " -t token=value\n"
<< " Defines a web token or parameter to pass to the application(s).\n"
<< " This simulates a <param> entry in an <object> tag.\n\n"
<< " -w [toplevel|embedded|fullscreen|hidden]\n"
<< " Specify the type of graphic window to create. If you specify\n" << " Specify the type of graphic window to create. If you specify\n"
<< " \"embedded\", a new window is created to be the parent.\n\n" << " \"embedded\", a new window is created to be the parent.\n\n"
@ -775,6 +789,33 @@ usage() {
<< DTOOL_PLATFORM << "\" .\n\n"; << DTOOL_PLATFORM << "\" .\n\n";
} }
////////////////////////////////////////////////////////////////////
// Function: Panda3D::parse_token
// Access: Private
// Description: Parses a web token of the form token=value, and
// stores it in _tokens. Returns true on success, false
// on failure.
////////////////////////////////////////////////////////////////////
bool Panda3D::
parse_token(char *arg) {
char *equals = strchr(arg, '=');
if (equals == NULL) {
return false;
}
// Directly munge the C string to truncate it at the equals sign.
// Classic C tricks.
*equals = '\0';
P3D_token token;
token._keyword = strdup(arg);
token._value = strdup(equals + 1);
*equals = '=';
_tokens.push_back(token);
return true;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: Panda3D::parse_int_pair // Function: Panda3D::parse_int_pair
// Access: Private // Access: Private
@ -857,13 +898,13 @@ st_timer_callback(EventLoopTimerRef timer, void *user_data) {
void Panda3D:: void Panda3D::
timer_callback(EventLoopTimerRef timer) { timer_callback(EventLoopTimerRef timer) {
// Check for new requests from the Panda3D plugin. // Check for new requests from the Panda3D plugin.
P3D_instance *inst = P3D_check_request(false); P3D_instance *inst = P3D_check_request(0.0);
while (inst != (P3D_instance *)NULL) { while (inst != (P3D_instance *)NULL) {
P3D_request *request = P3D_instance_get_request(inst); P3D_request *request = P3D_instance_get_request(inst);
if (request != (P3D_request *)NULL) { if (request != (P3D_request *)NULL) {
handle_request(request); handle_request(request);
} }
inst = P3D_check_request(false); inst = P3D_check_request(0.0);
} }
// Check the download tasks. // Check the download tasks.

View File

@ -63,6 +63,7 @@ private:
void delete_instance(P3D_instance *instance); void delete_instance(P3D_instance *instance);
void usage(); void usage();
bool parse_token(char *arg);
bool parse_int_pair(char *arg, int &x, int &y); bool parse_int_pair(char *arg, int &x, int &y);
void report_downloading_package(P3D_instance *instance); void report_downloading_package(P3D_instance *instance);
@ -83,6 +84,9 @@ private:
typedef pset<P3D_instance *> Instances; typedef pset<P3D_instance *> Instances;
Instances _instances; Instances _instances;
typedef pvector<P3D_token> Tokens;
Tokens _tokens;
// This nested class keeps track of active URL requests. // This nested class keeps track of active URL requests.
class URLGetter { class URLGetter {
public: public: