Commit 18547c31 authored by Thomas Grill's avatar Thomas Grill
Browse files

hopefully last static definitions bashed...

parent 5d61d7ab
...@@ -997,6 +997,8 @@ private: ...@@ -997,6 +997,8 @@ private:
//! Flush messages in the queue //! Flush messages in the queue
static void QFlush(flext_base *th = NULL); static void QFlush(flext_base *th = NULL);
static bool qustarted;
#if FLEXT_SYS == FLEXT_SYS_PD #if FLEXT_SYS == FLEXT_SYS_PD
static void SetGfx(t_classid c); static void SetGfx(t_classid c);
......
...@@ -31,11 +31,11 @@ $LastChangedBy$ ...@@ -31,11 +31,11 @@ $LastChangedBy$
#ifdef FLEXT_THREADS #ifdef FLEXT_THREADS
//! Thread id of message queue thread //! Thread id of message queue thread
flext::thrid_t flext::thrmsgid; FLEXT_TEMPIMPL(FLEXT_CLASSDEF(flext)::thrid_t FLEXT_CLASSDEF(flext))::thrmsgid;
#endif #endif
static bool qustarted = false; FLEXT_TEMPIMPL(bool FLEXT_CLASSDEF(flext_base))::qustarted = false;
#ifdef FLEXT_SHARED #ifdef FLEXT_SHARED
/* /*
For the shared version it _should_ be possible to have only one queue for all externals. For the shared version it _should_ be possible to have only one queue for all externals.
...@@ -54,6 +54,7 @@ public: ...@@ -54,6 +54,7 @@ public:
~QueueFifo(); ~QueueFifo();
}; };
template<typename=void>
class Queue: class Queue:
public flext, public flext,
public QueueFifo public QueueFifo
...@@ -62,11 +63,10 @@ public: ...@@ -62,11 +63,10 @@ public:
inline bool Empty() const { return !Avail(); } inline bool Empty() const { return !Avail(); }
inline void Push(MsgBundle *m); // defined after MsgBundle (gcc 3.3. won't take it otherwise...) inline void Push(MsgBundle *m); // defined after MsgBundle (gcc 3.3. won't take it otherwise...)
static Queue queue;
}; };
static Queue queue;
#define STATSIZE 8 #define STATSIZE 8
FLEXT_TEMPIMPL(class FLEXT_CLASSDEF(flext))::MsgBundle: FLEXT_TEMPIMPL(class FLEXT_CLASSDEF(flext))::MsgBundle:
...@@ -76,7 +76,7 @@ FLEXT_TEMPIMPL(class FLEXT_CLASSDEF(flext))::MsgBundle: ...@@ -76,7 +76,7 @@ FLEXT_TEMPIMPL(class FLEXT_CLASSDEF(flext))::MsgBundle:
public: public:
static MsgBundle *New() static MsgBundle *New()
{ {
MsgBundle *m = queue.New(); MsgBundle *m = Queue<>::queue.New();
m->msg.Init(); m->msg.Init();
return m; return m;
} }
...@@ -90,7 +90,7 @@ public: ...@@ -90,7 +90,7 @@ public:
mi = mn; mi = mn;
} }
m->msg.Free(); m->msg.Free();
queue.Free(m); Queue<>::queue.Free(m);
} }
bool BelongsTo(flext_base *t) const bool BelongsTo(flext_base *t) const
...@@ -333,7 +333,8 @@ QueueFifo::~QueueFifo() ...@@ -333,7 +333,8 @@ QueueFifo::~QueueFifo()
while((n = Get()) != NULL) delete n; while((n = Get()) != NULL) delete n;
} }
inline void Queue::Push(MsgBundle *m) template<typename T>
inline void Queue<T>::Push(MsgBundle *m)
{ {
if(LIKELY(m)) { if(LIKELY(m)) {
Put(m); Put(m);
...@@ -341,14 +342,21 @@ inline void Queue::Push(MsgBundle *m) ...@@ -341,14 +342,21 @@ inline void Queue::Push(MsgBundle *m)
} }
} }
template<typename=void>
struct QVars {
#if FLEXT_QMODE == 2
static flext::ThrCond qthrcond;
#elif FLEXT_QMODE == 0
static t_clock *qclk;
#endif
};
#if FLEXT_QMODE == 2 #if FLEXT_QMODE == 2
static flext::ThrCond qthrcond; template<> flext::ThrCond QVars<>::qthrcond;
#elif FLEXT_QMODE == 0 #elif FLEXT_QMODE
//static t_qelem *qclk = NULL; template<> t_clock *QVars<>::qclk = NULL;
static t_clock *qclk = NULL;
#endif #endif
#define CHUNK 10 #define CHUNK 10
#if FLEXT_QMODE == 1 #if FLEXT_QMODE == 1
...@@ -376,7 +384,7 @@ template<typename=void> bool QWork(bool syslock,flext_base *flushobj = NULL) ...@@ -376,7 +384,7 @@ template<typename=void> bool QWork(bool syslock,flext_base *flushobj = NULL)
#else #else
template<typename=void> bool QWork(bool syslock,flext_base *flushobj = NULL) template<typename=void> bool QWork(bool syslock,flext_base *flushobj = NULL)
{ {
Queue newmsgs; Queue<> newmsgs;
flext::MsgBundle *q; flext::MsgBundle *q;
#if 0 #if 0
...@@ -389,13 +397,13 @@ template<typename=void> bool QWork(bool syslock,flext_base *flushobj = NULL) ...@@ -389,13 +397,13 @@ template<typename=void> bool QWork(bool syslock,flext_base *flushobj = NULL)
// qc will be a minimum guaranteed number of present queue elements. // qc will be a minimum guaranteed number of present queue elements.
// On the other hand, if new queue elements are added by the methods called // On the other hand, if new queue elements are added by the methods called
// in the loop, these will be sent in the next tick to avoid recursion overflow. // in the loop, these will be sent in the next tick to avoid recursion overflow.
if(!queue.Avail()) break; if(!Queue<>::queue.Avail()) break;
#if FLEXT_QMODE == 2 #if FLEXT_QMODE == 2
if(syslock) flext::Lock(); if(syslock) flext::Lock();
#endif #endif
while((q = queue.Get()) != NULL) { while((q = Queue<>::queue.Get()) != NULL) {
if(q->Send()) if(q->Send())
newmsgs.Push(q); // remember messages to be processed again newmsgs.Push(q); // remember messages to be processed again
else else
...@@ -411,11 +419,11 @@ template<typename=void> bool QWork(bool syslock,flext_base *flushobj = NULL) ...@@ -411,11 +419,11 @@ template<typename=void> bool QWork(bool syslock,flext_base *flushobj = NULL)
// enqueue messages that have to be processed again // enqueue messages that have to be processed again
while((q = newmsgs.Get()) != NULL) while((q = newmsgs.Get()) != NULL)
if(!flushobj || !q->BelongsTo(flushobj)) if(!flushobj || !q->BelongsTo(flushobj))
queue.Push(q); Queue<>::queue.Push(q);
else else
flext::MsgBundle::Free(q); flext::MsgBundle::Free(q);
return queue.Avail(); return Queue<>::queue.Avail();
} }
#endif #endif
...@@ -463,7 +471,7 @@ But then the order of sent messages is not as intended ...@@ -463,7 +471,7 @@ But then the order of sent messages is not as intended
FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_base))::QFlush(flext_base *th) FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_base))::QFlush(flext_base *th)
{ {
FLEXT_ASSERT(!IsThreadRegistered()); FLEXT_ASSERT(!IsThreadRegistered());
while(!queue.Empty()) QWork(false,th); while(!Queue<>::queue.Empty()) QWork(false,th);
} }
template<typename> template<typename>
...@@ -472,7 +480,7 @@ void Trigger() ...@@ -472,7 +480,7 @@ void Trigger()
#if FLEXT_SYS == FLEXT_SYS_PD #if FLEXT_SYS == FLEXT_SYS_PD
# if FLEXT_QMODE == 2 # if FLEXT_QMODE == 2
// wake up worker thread // wake up worker thread
qthrcond.Signal(); QVars<>::qthrcond.Signal();
# elif FLEXT_QMODE == 1 && !defined(PERMANENTIDLE) # elif FLEXT_QMODE == 1 && !defined(PERMANENTIDLE)
if(!qtickactive) { if(!qtickactive) {
sys_callback(QTick<>,NULL,0); sys_callback(QTick<>,NULL,0);
...@@ -485,13 +493,13 @@ void Trigger() ...@@ -485,13 +493,13 @@ void Trigger()
bool sys = true; bool sys = true;
# endif # endif
if(!sys) flext::Lock(); if(!sys) flext::Lock();
clock_delay(qclk,0); clock_delay(QVars<>::qclk,0);
if(!sys) flext::Unlock(); if(!sys) flext::Unlock();
# endif # endif
#elif FLEXT_SYS == FLEXT_SYS_MAX #elif FLEXT_SYS == FLEXT_SYS_MAX
# if FLEXT_QMODE == 0 # if FLEXT_QMODE == 0
// qelem_front(qclk); // qelem_front(QVars<>::qclk);
clock_delay(qclk,0); clock_delay(QVars<>::qclk,0);
# endif # endif
#else #else
# error Not implemented # error Not implemented
...@@ -505,7 +513,7 @@ FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_base))::QWorker(thr_params *) ...@@ -505,7 +513,7 @@ FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_base))::QWorker(thr_params *)
qustarted = true; qustarted = true;
for(;;) { for(;;) {
// we need a timed wait so that idle processing can take place // we need a timed wait so that idle processing can take place
qthrcond.TimedWait(0.001); QVars<>::qthrcond.TimedWait(0.001);
QWork(true); QWork(true);
} }
} }
...@@ -525,7 +533,7 @@ FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_base))::StartQueue() ...@@ -525,7 +533,7 @@ FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_base))::StartQueue()
while(!qustarted) Sleep(0.001); while(!qustarted) Sleep(0.001);
#elif FLEXT_QMODE == 0 && (FLEXT_SYS == FLEXT_SYS_PD || FLEXT_SYS == FLEXT_SYS_MAX) #elif FLEXT_QMODE == 0 && (FLEXT_SYS == FLEXT_SYS_PD || FLEXT_SYS == FLEXT_SYS_MAX)
// qclk = (t_qelem *)(qelem_new(NULL,(t_method)QTick<>)); // qclk = (t_qelem *)(qelem_new(NULL,(t_method)QTick<>));
qclk = (t_clock *)(clock_new(NULL,(t_method)QTick<>)); QVars<>::qclk = (t_clock *)(clock_new(NULL,(t_method)QTick<>));
qustarted = true; qustarted = true;
#else #else
# error Not implemented! # error Not implemented!
...@@ -545,12 +553,12 @@ FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext))::MsgFree(MsgBundle *m) ...@@ -545,12 +553,12 @@ FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext))::MsgFree(MsgBundle *m)
FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext))::ToSysMsg(MsgBundle *m) FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext))::ToSysMsg(MsgBundle *m)
{ {
m->Send(); m->Send();
queue.Free(m); Queue<>::queue.Free(m);
} }
FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext))::ToQueueMsg(MsgBundle *m) FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext))::ToQueueMsg(MsgBundle *m)
{ {
queue.Push(m); Queue<>::queue.Push(m);
} }
...@@ -559,49 +567,49 @@ FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_base))::ToQueueBang(int o) const ...@@ -559,49 +567,49 @@ FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_base))::ToQueueBang(int o) const
{ {
MsgBundle *m = MsgBundle::New(); MsgBundle *m = MsgBundle::New();
m->Add(const_cast<flext_base *>(this),o); m->Add(const_cast<flext_base *>(this),o);
queue.Push(m); Queue<>::queue.Push(m);
} }
FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_base))::ToQueueFloat(int o,float f) const FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_base))::ToQueueFloat(int o,float f) const
{ {
MsgBundle *m = MsgBundle::New(); MsgBundle *m = MsgBundle::New();
m->Add(const_cast<flext_base *>(this),o,f); m->Add(const_cast<flext_base *>(this),o,f);
queue.Push(m); Queue<>::queue.Push(m);
} }
FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_base))::ToQueueInt(int o,int f) const FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_base))::ToQueueInt(int o,int f) const
{ {
MsgBundle *m = MsgBundle::New(); MsgBundle *m = MsgBundle::New();
m->Add(const_cast<flext_base *>(this),o,f); m->Add(const_cast<flext_base *>(this),o,f);
queue.Push(m); Queue<>::queue.Push(m);
} }
FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_base))::ToQueueSymbol(int o,const t_symbol *s) const FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_base))::ToQueueSymbol(int o,const t_symbol *s) const
{ {
MsgBundle *m = MsgBundle::New(); MsgBundle *m = MsgBundle::New();
m->Add(const_cast<flext_base *>(this),o,s); m->Add(const_cast<flext_base *>(this),o,s);
queue.Push(m); Queue<>::queue.Push(m);
} }
FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_base))::ToQueueAtom(int o,const t_atom &at) const FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_base))::ToQueueAtom(int o,const t_atom &at) const
{ {
MsgBundle *m = MsgBundle::New(); MsgBundle *m = MsgBundle::New();
m->Add(const_cast<flext_base *>(this),o,at); m->Add(const_cast<flext_base *>(this),o,at);
queue.Push(m); Queue<>::queue.Push(m);
} }
FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_base))::ToQueueList(int o,int argc,const t_atom *argv) const FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_base))::ToQueueList(int o,int argc,const t_atom *argv) const
{ {
MsgBundle *m = MsgBundle::New(); MsgBundle *m = MsgBundle::New();
m->Add(const_cast<flext_base *>(this),o,argc,argv); m->Add(const_cast<flext_base *>(this),o,argc,argv);
queue.Push(m); Queue<>::queue.Push(m);
} }
FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_base))::ToQueueAnything(int o,const t_symbol *s,int argc,const t_atom *argv) const FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_base))::ToQueueAnything(int o,const t_symbol *s,int argc,const t_atom *argv) const
{ {
MsgBundle *m = MsgBundle::New(); MsgBundle *m = MsgBundle::New();
m->Add(const_cast<flext_base *>(this),o,s,argc,argv); m->Add(const_cast<flext_base *>(this),o,s,argc,argv);
queue.Push(m); Queue<>::queue.Push(m);
} }
...@@ -663,7 +671,7 @@ FLEXT_TEMPIMPL(bool FLEXT_CLASSDEF(flext))::QueueForward(const t_symbol *recv,co ...@@ -663,7 +671,7 @@ FLEXT_TEMPIMPL(bool FLEXT_CLASSDEF(flext))::QueueForward(const t_symbol *recv,co
MsgBundle *m = MsgBundle::New(); MsgBundle *m = MsgBundle::New();
m->Add(recv,s,argc,argv); m->Add(recv,s,argc,argv);
// send over queue // send over queue
queue.Push(m); Queue<>::queue.Push(m);
return true; return true;
} }
...@@ -678,7 +686,7 @@ FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_base))::AddIdle() ...@@ -678,7 +686,7 @@ FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_base))::AddIdle()
MsgBundle *m = MsgBundle::New(); MsgBundle *m = MsgBundle::New();
m->Idle(const_cast<flext_base *>(this)); m->Idle(const_cast<flext_base *>(this));
// send over queue // send over queue
queue.Push(m); Queue<>::queue.Push(m);
} }
FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_base))::AddIdle(bool (*idlefun)(int argc,const t_atom *argv),int argc,const t_atom *argv) FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_base))::AddIdle(bool (*idlefun)(int argc,const t_atom *argv),int argc,const t_atom *argv)
...@@ -686,7 +694,7 @@ FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_base))::AddIdle(bool (*idlefun)(int arg ...@@ -686,7 +694,7 @@ FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext_base))::AddIdle(bool (*idlefun)(int arg
MsgBundle *m = MsgBundle::New(); MsgBundle *m = MsgBundle::New();
m->Idle(idlefun,argc,argv); m->Idle(idlefun,argc,argv);
// send over queue // send over queue
queue.Push(m); Queue<>::queue.Push(m);
} }
#include "flpopns.h" #include "flpopns.h"
......
...@@ -107,9 +107,8 @@ public: ...@@ -107,9 +107,8 @@ public:
}; };
template<typename=void> template<typename=void>
class ThrRegistry struct ThrRegistry
{ {
public:
static ThrFinder< PooledLifo<thr_entry,1,10> > pending; static ThrFinder< PooledLifo<thr_entry,1,10> > pending;
static ThrFinder< TypedLifo<thr_entry> > active,stopped; static ThrFinder< TypedLifo<thr_entry> > active,stopped;
}; };
...@@ -135,35 +134,26 @@ public: ...@@ -135,35 +134,26 @@ public:
} }
}; };
#if 0 template<typename=void>
class ThrIdCell struct ThrVars {
: public LifoCell // this should _definitely_ be a hashmap....
, public ThrId // \TODO above all it should be populated immediately, otherwise it could easily happen
{ // that the passing on to the set happens too late! We need that lockfree set!
public: static std::set<ThrId> regthreads;
ThrIdCell(const thrid_t &_id): ThrId(_id) {}
};
class RegQueue
: public TypedLifo<ThrIdCell>
{
public:
~RegQueue() { ThrIdCell *pid; while((pid = Pop()) != NULL) delete pid; }
};
static RegQueue regqueue,unregqueue; //! Registry lock
#endif static flext::ThrMutex *thrregmtx;
// this should _definitely_ be a hashmap.... //! Helper thread conditional
// \TODO above all it should be populated immediately, otherwise it could easily happen static flext::ThrCond *thrhelpcond;
// that the passing on to the set happens too late! We need that lockfree set!
static std::set<ThrId> regthreads;
//! Registry lock static bool initialized;
static flext::ThrMutex *thrregmtx = NULL; };
//! Helper thread conditional template<> std::set<ThrId> ThrVars<>::regthreads;
static flext::ThrCond *thrhelpcond = NULL; template<> flext::ThrMutex *ThrVars<>::thrregmtx = NULL;
template<> flext::ThrCond *ThrVars<>::thrhelpcond = NULL;
template<> bool ThrVars<>::initialized = false;
static void LaunchHelper(thr_entry *e) static void LaunchHelper(thr_entry *e)
{ {
...@@ -173,13 +163,11 @@ static void LaunchHelper(thr_entry *e) ...@@ -173,13 +163,11 @@ static void LaunchHelper(thr_entry *e)
flext::UnregisterThread(e->thrid); flext::UnregisterThread(e->thrid);
} }
bool initialized = false;
//! Start helper thread //! Start helper thread
FLEXT_TEMPIMPL(bool FLEXT_CLASSDEF(flext))::StartHelper() FLEXT_TEMPIMPL(bool FLEXT_CLASSDEF(flext))::StartHelper()
{ {
bool ok = false; bool ok = false;
initialized = false; ThrVars<>::initialized = false;
thrregmtx = new ThrMutex; thrregmtx = new ThrMutex;
...@@ -207,7 +195,7 @@ FLEXT_TEMPIMPL(bool FLEXT_CLASSDEF(flext))::StartHelper() ...@@ -207,7 +195,7 @@ FLEXT_TEMPIMPL(bool FLEXT_CLASSDEF(flext))::StartHelper()
error("flext - Could not launch helper thread!"); error("flext - Could not launch helper thread!");
else { else {
// now we have to wait for thread helper to initialize // now we have to wait for thread helper to initialize
while(!initialized) Sleep(0.001); while(!ThrVars<>::initialized) Sleep(0.001);
// we are ready for threading now! // we are ready for threading now!
} }
...@@ -236,7 +224,7 @@ FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext))::ThrHelper(void *) ...@@ -236,7 +224,7 @@ FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext))::ThrHelper(void *)
thrhelpcond = new ThrCond; thrhelpcond = new ThrCond;
initialized = true; ThrVars<>::initialized = true;
// helper loop // helper loop
for(;;) { for(;;) {
......
...@@ -32,21 +32,30 @@ $LastChangedBy$ ...@@ -32,21 +32,30 @@ $LastChangedBy$
#include "flpushns.h" #include "flpushns.h"
template<typename=void> double getstarttime();
template<typename=void>
struct TimerVars
{
#if FLEXT_OS == FLEXT_OS_WIN #if FLEXT_OS == FLEXT_OS_WIN
static double perffrq = 0; static double perffrq;
#endif #endif
static double starttime;
};
static double getstarttime(); #if FLEXT_OS == FLEXT_OS_WIN
static double starttime = getstarttime(); template<> double TimerVars<>::perffrq = 0;
#endif
template<> double TimerVars<>::starttime = getstarttime();
static double getstarttime() template<typename> double getstarttime()
{ {
#if FLEXT_OS == FLEXT_OS_WIN #if FLEXT_OS == FLEXT_OS_WIN
LARGE_INTEGER frq; LARGE_INTEGER frq;
if(QueryPerformanceFrequency(&frq)) perffrq = (double)frq.QuadPart; if(QueryPerformanceFrequency(&frq)) TimerVars<>::perffrq = (double)frq.QuadPart;
#endif #endif
starttime = 0; TimerVars<>::starttime = 0;
return flext::GetOSTime(); return flext::GetOSTime();
} }
...@@ -57,7 +66,7 @@ FLEXT_TEMPIMPL(double FLEXT_CLASSDEF(flext))::GetOSTime() ...@@ -57,7 +66,7 @@ FLEXT_TEMPIMPL(double FLEXT_CLASSDEF(flext))::GetOSTime()
#if FLEXT_OS == FLEXT_OS_WIN #if FLEXT_OS == FLEXT_OS_WIN
LARGE_INTEGER cnt; LARGE_INTEGER cnt;
if(perffrq && QueryPerformanceCounter(&cnt)) if(perffrq && QueryPerformanceCounter(&cnt))
tm = cnt.QuadPart/perffrq; tm = cnt.QuadPart/TimerVars<>::perffrq;
else { else {
SYSTEMTIME systm; SYSTEMTIME systm;
FILETIME fltm; FILETIME fltm;
...@@ -76,7 +85,7 @@ FLEXT_TEMPIMPL(double FLEXT_CLASSDEF(flext))::GetOSTime() ...@@ -76,7 +85,7 @@ FLEXT_TEMPIMPL(double FLEXT_CLASSDEF(flext))::GetOSTime()
#else #else
#error Not implemented #error Not implemented
#endif #endif
return tm-starttime; return tm-TimerVars<>::starttime;
} }
FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext))::Sleep(double s) FLEXT_TEMPIMPL(void FLEXT_CLASSDEF(flext))::Sleep(double s)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment