mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 02:15:43 -04:00
Changes to support yielding instead of sleeping
This commit is contained in:
parent
ed9eb66867
commit
ffa480bde7
@ -87,7 +87,7 @@ class ConnectionRepository(
|
|||||||
|
|
||||||
# This DatagramIterator is constructed once, and then re-used
|
# This DatagramIterator is constructed once, and then re-used
|
||||||
# each time we read a datagram.
|
# each time we read a datagram.
|
||||||
self.__di = PyDatagramIterator()
|
self.private__di = PyDatagramIterator()
|
||||||
|
|
||||||
self.recorder = None
|
self.recorder = None
|
||||||
|
|
||||||
@ -529,8 +529,8 @@ class ConnectionRepository(
|
|||||||
|
|
||||||
def readerPollOnce(self):
|
def readerPollOnce(self):
|
||||||
if self.checkDatagram():
|
if self.checkDatagram():
|
||||||
self.getDatagramIterator(self.__di)
|
self.getDatagramIterator(self.private__di)
|
||||||
self.handleDatagram(self.__di)
|
self.handleDatagram(self.private__di)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
# Unable to receive a datagram: did we lose the connection?
|
# Unable to receive a datagram: did we lose the connection?
|
||||||
|
@ -28,7 +28,13 @@
|
|||||||
#include "throw_event.h"
|
#include "throw_event.h"
|
||||||
#include "pStatTimer.h"
|
#include "pStatTimer.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_PYTHON
|
||||||
|
#ifndef CPPPARSER
|
||||||
|
#include "py_panda.h"
|
||||||
|
IMPORT_THIS struct Dtool_PyTypedObject Dtool_DatagramIterator;
|
||||||
|
IMPORT_THIS struct Dtool_PyTypedObject Dtool_DCClass;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
const string CConnectionRepository::_overflow_event_name = "CRDatagramOverflow";
|
const string CConnectionRepository::_overflow_event_name = "CRDatagramOverflow";
|
||||||
|
|
||||||
@ -45,6 +51,7 @@ CConnectionRepository::
|
|||||||
CConnectionRepository(bool has_owner_view) :
|
CConnectionRepository(bool has_owner_view) :
|
||||||
#ifdef HAVE_PYTHON
|
#ifdef HAVE_PYTHON
|
||||||
_python_repository(NULL),
|
_python_repository(NULL),
|
||||||
|
_python_ai_datagramiterator(NULL),
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_OPENSSL
|
#ifdef HAVE_OPENSSL
|
||||||
_http_conn(NULL),
|
_http_conn(NULL),
|
||||||
@ -54,7 +61,7 @@ CConnectionRepository(bool has_owner_view) :
|
|||||||
_qcr(&_qcm, 0),
|
_qcr(&_qcm, 0),
|
||||||
#endif
|
#endif
|
||||||
#ifdef WANT_NATIVE_NET
|
#ifdef WANT_NATIVE_NET
|
||||||
_bdc(0,4096000,4096000,1460),
|
_bdc(4096000,4096000,1400),
|
||||||
_native(false),
|
_native(false),
|
||||||
#endif
|
#endif
|
||||||
_client_datagram(true),
|
_client_datagram(true),
|
||||||
@ -70,6 +77,14 @@ CConnectionRepository(bool has_owner_view) :
|
|||||||
_qcr.start_delay(min_lag, max_lag);
|
_qcr.start_delay(min_lag, max_lag);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_PYTHON
|
||||||
|
PyObject * PyDitterator = DTool_CreatePyInstance(&_di,Dtool_DatagramIterator,false,false);
|
||||||
|
if(PyDitterator != NULL)
|
||||||
|
_python_ai_datagramiterator = Py_BuildValue("(O)",PyDitterator);
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -297,6 +312,9 @@ check_datagram() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: CConnectionRepository::is_connected
|
// Function: CConnectionRepository::is_connected
|
||||||
// Access: Published
|
// Access: Published
|
||||||
@ -542,7 +560,8 @@ handle_update_field() {
|
|||||||
#ifdef HAVE_PYTHON
|
#ifdef HAVE_PYTHON
|
||||||
PStatTimer timer(_update_pcollector);
|
PStatTimer timer(_update_pcollector);
|
||||||
unsigned int do_id = _di.get_uint32();
|
unsigned int do_id = _di.get_uint32();
|
||||||
if (_python_repository != (PyObject *)NULL) {
|
if (_python_repository != (PyObject *)NULL)
|
||||||
|
{
|
||||||
PyObject *doId2do =
|
PyObject *doId2do =
|
||||||
PyObject_GetAttrString(_python_repository, "doId2do");
|
PyObject_GetAttrString(_python_repository, "doId2do");
|
||||||
nassertr(doId2do != NULL, false);
|
nassertr(doId2do != NULL, false);
|
||||||
@ -560,6 +579,7 @@ handle_update_field() {
|
|||||||
PyObject *dclass_obj = PyObject_GetAttrString(distobj, "dclass");
|
PyObject *dclass_obj = PyObject_GetAttrString(distobj, "dclass");
|
||||||
nassertr(dclass_obj != NULL, false);
|
nassertr(dclass_obj != NULL, false);
|
||||||
|
|
||||||
|
|
||||||
PyObject *dclass_this = PyObject_GetAttrString(dclass_obj, "this");
|
PyObject *dclass_this = PyObject_GetAttrString(dclass_obj, "this");
|
||||||
Py_DECREF(dclass_obj);
|
Py_DECREF(dclass_obj);
|
||||||
nassertr(dclass_this != NULL, false);
|
nassertr(dclass_this != NULL, false);
|
||||||
@ -567,6 +587,7 @@ handle_update_field() {
|
|||||||
DCClass *dclass = (DCClass *)PyInt_AsLong(dclass_this);
|
DCClass *dclass = (DCClass *)PyInt_AsLong(dclass_this);
|
||||||
Py_DECREF(dclass_this);
|
Py_DECREF(dclass_this);
|
||||||
|
|
||||||
|
|
||||||
// It's a good idea to ensure the reference count to distobj is
|
// It's a good idea to ensure the reference count to distobj is
|
||||||
// raised while we call the update method--otherwise, the update
|
// raised while we call the update method--otherwise, the update
|
||||||
// method might get into trouble if it tried to delete the
|
// method might get into trouble if it tried to delete the
|
||||||
@ -582,10 +603,10 @@ handle_update_field() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
#endif // HAVE_PYTHON
|
#endif // HAVE_PYTHON
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: CConnectionRepository::handle_update_field_owner
|
// Function: CConnectionRepository::handle_update_field_owner
|
||||||
// Access: Private
|
// Access: Private
|
||||||
@ -820,3 +841,116 @@ describe_message(ostream &out, const string &prefix,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_PYTHON
|
||||||
|
#ifdef WANT_NATIVE_NET
|
||||||
|
|
||||||
|
bool CConnectionRepository::network_based_reader_and_yielder(PyObject *PycallBackFunction,ClockObject &clock, float returnBy)
|
||||||
|
{
|
||||||
|
bool KeepRunning = true;
|
||||||
|
while(KeepRunning)
|
||||||
|
{
|
||||||
|
check_datagram_ai(PycallBackFunction);
|
||||||
|
_bdc.Flush();
|
||||||
|
float currentTime = clock.get_real_time();
|
||||||
|
float dif_time = returnBy - currentTime;
|
||||||
|
if(dif_time <= 0.001) // to avoi over runs..
|
||||||
|
break;
|
||||||
|
_bdc.WaitForNetworkReadEvent(dif_time);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CConnectionRepository::check_datagram_ai(PyObject *PycallBackFunction)
|
||||||
|
{
|
||||||
|
// these could be static .. not
|
||||||
|
PyObject *doId2do = NULL;
|
||||||
|
|
||||||
|
// this seems weird...here
|
||||||
|
_bdc.Flush();
|
||||||
|
while (_bdc.GetMessage(_dg))
|
||||||
|
{
|
||||||
|
if (get_verbose())
|
||||||
|
describe_message(nout, "RECV", _dg);
|
||||||
|
|
||||||
|
// Start breaking apart the datagram.
|
||||||
|
_di.assign(_dg);
|
||||||
|
unsigned char wc_cnt = _di.get_uint8();
|
||||||
|
_msg_channels.clear();
|
||||||
|
for(unsigned char lp1 = 0; lp1 < wc_cnt; lp1++)
|
||||||
|
_msg_channels.push_back(_di.get_uint64());
|
||||||
|
|
||||||
|
_msg_sender = _di.get_uint64();
|
||||||
|
_msg_type = _di.get_uint16();
|
||||||
|
|
||||||
|
if( _msg_type == STATESERVER_OBJECT_UPDATE_FIELD)
|
||||||
|
{
|
||||||
|
if(doId2do == NULL)
|
||||||
|
{
|
||||||
|
// this is my attemp to take it out of the inner loop RHH
|
||||||
|
doId2do =PyObject_GetAttrString(_python_repository, "doId2do");
|
||||||
|
nassertr(doId2do != NULL, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!handle_update_field_ai(doId2do))
|
||||||
|
{
|
||||||
|
Py_XDECREF(doId2do);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PyObject * result = PyEval_CallObject(PycallBackFunction, _python_ai_datagramiterator);
|
||||||
|
if (PyErr_Occurred())
|
||||||
|
{
|
||||||
|
Py_XDECREF(doId2do);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_XDECREF(doId2do);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // #ifdef WANT_NATIVE_NET
|
||||||
|
#endif // #ifdef HAVE_PYTHON
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_PYTHON
|
||||||
|
#ifdef WANT_NATIVE_NET
|
||||||
|
|
||||||
|
|
||||||
|
bool CConnectionRepository::handle_update_field_ai(PyObject *doId2do)
|
||||||
|
{
|
||||||
|
PStatTimer timer(_update_pcollector);
|
||||||
|
unsigned int do_id = _di.get_uint32();
|
||||||
|
|
||||||
|
PyObject *doId = PyLong_FromUnsignedLong(do_id);
|
||||||
|
PyObject *distobj = PyDict_GetItem(doId2do, doId);
|
||||||
|
Py_DECREF(doId);
|
||||||
|
|
||||||
|
if (distobj != NULL)
|
||||||
|
{
|
||||||
|
PyObject *dclass_obj = PyObject_GetAttrString(distobj, "dclass");
|
||||||
|
nassertr(dclass_obj != NULL, false);
|
||||||
|
|
||||||
|
DCClass *dclass = NULL;
|
||||||
|
DTOOL_Call_ExtractThisPointerForType(dclass_obj, &Dtool_DCClass, (void **) &dclass);
|
||||||
|
if(dclass == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Py_INCREF(distobj);
|
||||||
|
dclass->receive_update(distobj, _di);
|
||||||
|
Py_DECREF(distobj);
|
||||||
|
|
||||||
|
if (PyErr_Occurred())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // #ifdef WANT_NATIVE_NET
|
||||||
|
#endif // #ifdef HAVE_PYTHON
|
@ -27,6 +27,7 @@
|
|||||||
#include "dcField.h" // to pick up Python.h
|
#include "dcField.h" // to pick up Python.h
|
||||||
#include "pStatCollector.h"
|
#include "pStatCollector.h"
|
||||||
#include "datagramIterator.h"
|
#include "datagramIterator.h"
|
||||||
|
#include "clockObject.h"
|
||||||
|
|
||||||
#ifdef HAVE_NET
|
#ifdef HAVE_NET
|
||||||
#include "queuedConnectionManager.h"
|
#include "queuedConnectionManager.h"
|
||||||
@ -98,6 +99,13 @@ PUBLISHED:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool check_datagram();
|
bool check_datagram();
|
||||||
|
#ifdef HAVE_PYTHON
|
||||||
|
#ifdef WANT_NATIVE_NET
|
||||||
|
bool check_datagram_ai(PyObject *PycallBackFunction);
|
||||||
|
bool network_based_reader_and_yielder(PyObject *PycallBackFunction,ClockObject &clock, float returnBy);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
INLINE void get_datagram(Datagram &dg);
|
INLINE void get_datagram(Datagram &dg);
|
||||||
INLINE void get_datagram_iterator(DatagramIterator &di);
|
INLINE void get_datagram_iterator(DatagramIterator &di);
|
||||||
INLINE CHANNEL_TYPE get_msg_channel(int offset = 0) const;
|
INLINE CHANNEL_TYPE get_msg_channel(int offset = 0) const;
|
||||||
@ -125,6 +133,13 @@ PUBLISHED:
|
|||||||
INLINE bool get_verbose() const;
|
INLINE bool get_verbose() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
#ifdef HAVE_PYTHON
|
||||||
|
#ifdef WANT_NATIVE_NET
|
||||||
|
bool handle_update_field_ai(PyObject *doId2do);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
bool do_check_datagram();
|
bool do_check_datagram();
|
||||||
bool handle_update_field();
|
bool handle_update_field();
|
||||||
bool handle_update_field_owner();
|
bool handle_update_field_owner();
|
||||||
@ -134,6 +149,7 @@ private:
|
|||||||
|
|
||||||
#ifdef HAVE_PYTHON
|
#ifdef HAVE_PYTHON
|
||||||
PyObject *_python_repository;
|
PyObject *_python_repository;
|
||||||
|
PyObject *_python_ai_datagramiterator;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_OPENSSL
|
#ifdef HAVE_OPENSSL
|
||||||
|
@ -337,6 +337,8 @@ class TaskManager:
|
|||||||
self.__doLaterList = []
|
self.__doLaterList = []
|
||||||
|
|
||||||
self._profileFrames = False
|
self._profileFrames = False
|
||||||
|
self.MaxEpockSpeed = 1.0/30.0;
|
||||||
|
|
||||||
|
|
||||||
# We copy this value in from __builtins__ when it gets set.
|
# We copy this value in from __builtins__ when it gets set.
|
||||||
# But since the TaskManager might have to run before it gets
|
# But since the TaskManager might have to run before it gets
|
||||||
@ -363,6 +365,7 @@ class TaskManager:
|
|||||||
# A default task.
|
# A default task.
|
||||||
self.add(self.__doLaterProcessor, "doLaterProcessor", -10)
|
self.add(self.__doLaterProcessor, "doLaterProcessor", -10)
|
||||||
|
|
||||||
|
|
||||||
def stepping(self, value):
|
def stepping(self, value):
|
||||||
self.stepping = value
|
self.stepping = value
|
||||||
|
|
||||||
@ -410,6 +413,13 @@ class TaskManager:
|
|||||||
heapify(self.__doLaterList)
|
heapify(self.__doLaterList)
|
||||||
newLen = len(self.__doLaterList)
|
newLen = len(self.__doLaterList)
|
||||||
return oldLen - newLen
|
return oldLen - newLen
|
||||||
|
|
||||||
|
def __getNextDoLaterTime(self):
|
||||||
|
if self.__doLaterList:
|
||||||
|
dl = self.__doLaterList[0]
|
||||||
|
return dl.wakeTime
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
|
||||||
def __doLaterProcessor(self, task):
|
def __doLaterProcessor(self, task):
|
||||||
# Removing the tasks during the for loop is a bad idea
|
# Removing the tasks during the for loop is a bad idea
|
||||||
@ -784,6 +794,24 @@ class TaskManager:
|
|||||||
if num is None:
|
if num is None:
|
||||||
num = 1
|
num = 1
|
||||||
self._profileFrameCount = num
|
self._profileFrameCount = num
|
||||||
|
|
||||||
|
|
||||||
|
# in the event we want to do frame time managment.. this is the function to
|
||||||
|
# replace or overload..
|
||||||
|
def doYield(self , frameStartTime, nextScheuledTaksTime):
|
||||||
|
None
|
||||||
|
|
||||||
|
def doYieldExample(self , frameStartTime, nextScheuledTaksTime):
|
||||||
|
minFinTime = frameStartTime + self.MaxEpockSpeed
|
||||||
|
if nextScheuledTaksTime > 0 and nextScheuledTaksTime < minFinTime:
|
||||||
|
print ' Adjusting Time'
|
||||||
|
minFinTime = nextScheuledTaksTime;
|
||||||
|
delta = minFinTime - self.globalClock.getRealTime();
|
||||||
|
while(delta > 0.002):
|
||||||
|
print ' sleep %s'% (delta)
|
||||||
|
time.sleep(delta)
|
||||||
|
delta = minFinTime - self.globalClock.getRealTime();
|
||||||
|
|
||||||
|
|
||||||
@profiled()
|
@profiled()
|
||||||
def _doProfiledFrames(self, *args, **kArgs):
|
def _doProfiledFrames(self, *args, **kArgs):
|
||||||
@ -795,6 +823,7 @@ class TaskManager:
|
|||||||
def step(self):
|
def step(self):
|
||||||
# assert TaskManager.notify.debug('step: begin')
|
# assert TaskManager.notify.debug('step: begin')
|
||||||
self.currentTime, self.currentFrame = self.__getTimeFrame()
|
self.currentTime, self.currentFrame = self.__getTimeFrame()
|
||||||
|
startFrameTime = self.globalClock.getRealTime()
|
||||||
# Replace keyboard interrupt handler during task list processing
|
# Replace keyboard interrupt handler during task list processing
|
||||||
# so we catch the keyboard interrupt but don't handle it until
|
# so we catch the keyboard interrupt but don't handle it until
|
||||||
# after task list processing is complete.
|
# after task list processing is complete.
|
||||||
@ -839,11 +868,16 @@ class TaskManager:
|
|||||||
# Add new pending tasks
|
# Add new pending tasks
|
||||||
self.__addPendingTasksToTaskList()
|
self.__addPendingTasksToTaskList()
|
||||||
|
|
||||||
|
#this is the spot for a Internal Yield Function
|
||||||
|
nextTaskTime = self.__getNextDoLaterTime()
|
||||||
|
self.doYield(startFrameTime,nextTaskTime)
|
||||||
|
|
||||||
# Restore default interrupt handler
|
# Restore default interrupt handler
|
||||||
signal.signal(signal.SIGINT, signal.default_int_handler)
|
signal.signal(signal.SIGINT, signal.default_int_handler)
|
||||||
if self.fKeyboardInterrupt:
|
if self.fKeyboardInterrupt:
|
||||||
raise KeyboardInterrupt
|
raise KeyboardInterrupt
|
||||||
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
# Set the clock to have last frame's time in case we were
|
# Set the clock to have last frame's time in case we were
|
||||||
# Paused at the prompt for a long time
|
# Paused at the prompt for a long time
|
||||||
|
Loading…
x
Reference in New Issue
Block a user