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
# complete list that way.
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.actor.Actor',
'direct.fsm.FSM',
'direct.interval.IntervalGlobal',
'direct.particles.ParticleEffect',
'direct.directutil.Mopath')
'direct.showutil.*',
'direct.stdpy.*')
# Exclude these GUI toolkits; they're big, and many applications don't
# use them. We define them as separate, optional packages, below.

View File

@ -404,7 +404,8 @@ check_request() {
// Function: P3DInstanceManager::wait_request
// Access: Public
// 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
// to the possibility of race conditions, it is possible
// for this function to return when there is in fact no
@ -412,9 +413,60 @@ check_request() {
// the request first).
////////////////////////////////////////////////////////////////////
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();
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) {
#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) {
_request_ready.release();
return;
@ -425,7 +477,7 @@ wait_request() {
}
// No pending requests; go to sleep.
_request_ready.wait();
_request_ready.wait(timeout);
}
_request_ready.release();
}

View File

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

View File

@ -25,6 +25,7 @@
#include "p3dStringObject.h"
#include <assert.h>
#include <math.h>
// Use a simple lock to protect the C-style API functions in this
// module from parallel access by multiple threads in the host.
@ -405,21 +406,65 @@ P3D_instance_get_request(P3D_instance *instance) {
}
P3D_instance *
P3D_check_request(bool wait) {
P3D_check_request(double timeout) {
assert(P3DInstanceManager::get_global_ptr()->is_initialized());
ACQUIRE_LOCK(_api_lock);
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
P3D_instance *inst = inst_mgr->check_request();
if (inst != NULL || !wait) {
if (inst != NULL || timeout <= 0.0) {
RELEASE_LOCK(_api_lock);
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.
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) {
#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);
inst_mgr->wait_request();
inst_mgr->wait_request(timeout);
ACQUIRE_LOCK(_api_lock);
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
return a pointer to one of them (which you may then pass to
P3D_instance_get_request_func). If no instances have a pending
request, this function will return NULL. If wait is true, this
function will never return NULL unless there are no instances open;
instead, it will wait indefinitely until there is a request
available.
request, this function will return NULL. This function will not
return until at least timeout seconds have elapsed, or a request is
available, whichever comes first.
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
@ -749,7 +748,7 @@ P3D_instance_get_request_func(P3D_instance *instance);
should always verify that the return value of
P3D_instance_get_request() is not NULL. */
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
be passed here, after it has been handled, to deallocate its

View File

@ -36,6 +36,9 @@
#endif
// The amount of time in seconds to wait for new messages.
static const double wait_cycle = 0.2;
////////////////////////////////////////////////////////////////////
// Function: Panda3D::Constructor
// Access: Public
@ -61,7 +64,7 @@ run(int argc, char *argv[]) {
// We prefix a "+" sign to tell gnu getopt not to parse options
// following the first not-option parameter. (These will be passed
// 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;
string download_url = PANDA_PACKAGE_HOST_URL;
@ -92,7 +95,7 @@ run(int argc, char *argv[]) {
verify_contents = true;
break;
case 't':
case 'w':
if (strcmp(optarg, "toplevel") == 0) {
window_type = P3D_WT_toplevel;
} else if (strcmp(optarg, "embedded") == 0) {
@ -102,7 +105,14 @@ run(int argc, char *argv[]) {
} else if (strcmp(optarg, "hidden") == 0) {
window_type = P3D_WT_hidden;
} 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;
}
break;
@ -248,13 +258,13 @@ run(int argc, char *argv[]) {
DispatchMessage(&msg);
// 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) {
P3D_request *request = P3D_instance_get_request(inst);
if (request != (P3D_request *)NULL) {
handle_request(request);
}
inst = P3D_check_request(false);
inst = P3D_check_request(wait_cycle);
}
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
// generate Windows events. Instead, just wait for requests.
while (!_instances.empty()) {
P3D_instance *inst = P3D_check_request(false);
P3D_instance *inst = P3D_check_request(wait_cycle);
if (inst != (P3D_instance *)NULL) {
P3D_request *request = P3D_instance_get_request(inst);
if (request != (P3D_request *)NULL) {
@ -294,7 +304,7 @@ run(int argc, char *argv[]) {
EventLoopRef main_loop = GetMainEventLoop();
EventLoopTimerUPP timer_upp = NewEventLoopTimerUPP(st_timer_callback);
EventLoopTimerRef timer;
EventTimerInterval interval = 200 * kEventDurationMillisecond;
EventTimerInterval interval = wait_cycle * kEventDurationSecond;
InstallEventLoopTimer(main_loop, interval, interval,
timer_upp, this, &timer);
RunApplicationEventLoop();
@ -310,7 +320,7 @@ run(int argc, char *argv[]) {
// Now wait while we process pending requests.
while (!_instances.empty()) {
P3D_instance *inst = P3D_check_request(false);
P3D_instance *inst = P3D_check_request(wait_cycle);
if (inst != (P3D_instance *)NULL) {
P3D_request *request = P3D_instance_get_request(inst);
if (request != (P3D_request *)NULL) {
@ -647,7 +657,7 @@ create_instance(const string &p3d, P3D_window_type window_type,
}
// Build up the token list.
pvector<P3D_token> tokens;
Tokens tokens = _tokens;
P3D_token token;
string log_basename;
@ -745,7 +755,11 @@ usage() {
<< " time, but additional arguments may not be passed to any of the\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"
<< " \"embedded\", a new window is created to be the parent.\n\n"
@ -775,6 +789,33 @@ usage() {
<< 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
// Access: Private
@ -857,13 +898,13 @@ st_timer_callback(EventLoopTimerRef timer, void *user_data) {
void Panda3D::
timer_callback(EventLoopTimerRef timer) {
// 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) {
P3D_request *request = P3D_instance_get_request(inst);
if (request != (P3D_request *)NULL) {
handle_request(request);
}
inst = P3D_check_request(false);
inst = P3D_check_request(0.0);
}
// Check the download tasks.

View File

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