summaryrefslogtreecommitdiffstats
path: root/core/command_queue_mt.h
diff options
context:
space:
mode:
authorJuan Linietsky <reduzio@gmail.com>2014-02-09 22:10:30 -0300
committerJuan Linietsky <reduzio@gmail.com>2014-02-09 22:10:30 -0300
commit0b806ee0fc9097fa7bda7ac0109191c9c5e0a1ac (patch)
tree276c4d099e178eb67fbd14f61d77b05e3808e9e3 /core/command_queue_mt.h
parent0e49da1687bc8192ed210947da52c9e5c5f301bb (diff)
downloadredot-engine-0b806ee0fc9097fa7bda7ac0109191c9c5e0a1ac.tar.gz
GODOT IS OPEN SOURCE
Diffstat (limited to 'core/command_queue_mt.h')
-rw-r--r--core/command_queue_mt.h999
1 files changed, 999 insertions, 0 deletions
diff --git a/core/command_queue_mt.h b/core/command_queue_mt.h
new file mode 100644
index 0000000000..8b74b3b561
--- /dev/null
+++ b/core/command_queue_mt.h
@@ -0,0 +1,999 @@
+/*************************************************************************/
+/* command_queue_mt.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef COMMAND_QUEUE_MT_H
+#define COMMAND_QUEUE_MT_H
+
+#include "typedefs.h"
+#include "os/semaphore.h"
+#include "os/mutex.h"
+#include "os/memory.h"
+#include "simple_type.h"
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+
+class CommandQueueMT {
+
+ struct SyncSemaphore {
+
+ Semaphore *sem;
+ bool in_use;
+ };
+
+ struct CommandBase {
+
+ virtual void call()=0;
+ virtual ~CommandBase() {};
+ };
+
+ template<class T,class M>
+ struct Command0 : public CommandBase {
+
+ T*instance;
+ M method;
+
+ virtual void call() { (instance->*method)(); }
+ };
+
+ template<class T,class M,class P1>
+ struct Command1 : public CommandBase {
+
+ T*instance;
+ M method;
+ typename GetSimpleTypeT<P1>::type_t p1;
+
+ virtual void call() { (instance->*method)(p1); }
+ };
+
+ template<class T,class M,class P1,class P2>
+ struct Command2 : public CommandBase {
+
+ T*instance;
+ M method;
+ typename GetSimpleTypeT<P1>::type_t p1;
+ typename GetSimpleTypeT<P2>::type_t p2;
+
+ virtual void call() { (instance->*method)(p1,p2); }
+ };
+
+ template<class T,class M,class P1,class P2,class P3>
+ struct Command3 : public CommandBase {
+
+ T*instance;
+ M method;
+ typename GetSimpleTypeT<P1>::type_t p1;
+ typename GetSimpleTypeT<P2>::type_t p2;
+ typename GetSimpleTypeT<P3>::type_t p3;
+
+ virtual void call() { (instance->*method)(p1,p2,p3); }
+ };
+
+ template<class T,class M,class P1,class P2,class P3,class P4>
+ struct Command4 : public CommandBase {
+
+ T*instance;
+ M method;
+ typename GetSimpleTypeT<P1>::type_t p1;
+ typename GetSimpleTypeT<P2>::type_t p2;
+ typename GetSimpleTypeT<P3>::type_t p3;
+ typename GetSimpleTypeT<P4>::type_t p4;
+
+ virtual void call() { (instance->*method)(p1,p2,p3,p4); }
+ };
+
+ template<class T,class M,class P1,class P2,class P3,class P4,class P5>
+ struct Command5 : public CommandBase {
+
+ T*instance;
+ M method;
+ typename GetSimpleTypeT<P1>::type_t p1;
+ typename GetSimpleTypeT<P2>::type_t p2;
+ typename GetSimpleTypeT<P3>::type_t p3;
+ typename GetSimpleTypeT<P4>::type_t p4;
+ typename GetSimpleTypeT<P5>::type_t p5;
+
+ virtual void call() { (instance->*method)(p1,p2,p3,p4,p5); }
+ };
+
+ template<class T,class M,class P1,class P2,class P3,class P4,class P5,class P6>
+ struct Command6 : public CommandBase {
+
+ T*instance;
+ M method;
+ typename GetSimpleTypeT<P1>::type_t p1;
+ typename GetSimpleTypeT<P2>::type_t p2;
+ typename GetSimpleTypeT<P3>::type_t p3;
+ typename GetSimpleTypeT<P4>::type_t p4;
+ typename GetSimpleTypeT<P5>::type_t p5;
+ typename GetSimpleTypeT<P6>::type_t p6;
+
+ virtual void call() { (instance->*method)(p1,p2,p3,p4,p5,p6); }
+ };
+
+ template<class T,class M,class P1,class P2,class P3,class P4,class P5,class P6,class P7>
+ struct Command7 : public CommandBase {
+
+ T*instance;
+ M method;
+ typename GetSimpleTypeT<P1>::type_t p1;
+ typename GetSimpleTypeT<P2>::type_t p2;
+ typename GetSimpleTypeT<P3>::type_t p3;
+ typename GetSimpleTypeT<P4>::type_t p4;
+ typename GetSimpleTypeT<P5>::type_t p5;
+ typename GetSimpleTypeT<P6>::type_t p6;
+ typename GetSimpleTypeT<P7>::type_t p7;
+
+ virtual void call() { (instance->*method)(p1,p2,p3,p4,p5,p6,p7); }
+ };
+
+ /* comands that return */
+
+ template<class T,class M,class R>
+ struct CommandRet0 : public CommandBase {
+
+ T*instance;
+ M method;
+ R* ret;
+ SyncSemaphore *sync;
+
+ virtual void call() { *ret = (instance->*method)(); sync->sem->post(); sync->in_use=false; ; }
+ };
+
+ template<class T,class M,class P1,class R>
+ struct CommandRet1 : public CommandBase {
+
+ T*instance;
+ M method;
+ typename GetSimpleTypeT<P1>::type_t p1;
+ R* ret;
+ SyncSemaphore *sync;
+
+ virtual void call() { *ret = (instance->*method)(p1); sync->sem->post(); sync->in_use=false; ; }
+ };
+
+ template<class T,class M,class P1,class P2,class R>
+ struct CommandRet2 : public CommandBase {
+
+ T*instance;
+ M method;
+ typename GetSimpleTypeT<P1>::type_t p1;
+ typename GetSimpleTypeT<P2>::type_t p2;
+ R* ret;
+ SyncSemaphore *sync;
+
+ virtual void call() { *ret = (instance->*method)(p1,p2); sync->sem->post(); sync->in_use=false; ; }
+ };
+
+ template<class T,class M,class P1,class P2,class P3,class R>
+ struct CommandRet3 : public CommandBase {
+
+ T*instance;
+ M method;
+ typename GetSimpleTypeT<P1>::type_t p1;
+ typename GetSimpleTypeT<P2>::type_t p2;
+ typename GetSimpleTypeT<P3>::type_t p3;
+ R* ret;
+ SyncSemaphore *sync;
+
+ virtual void call() { *ret = (instance->*method)(p1,p2,p3); sync->sem->post(); sync->in_use=false; ; }
+ };
+
+ template<class T,class M,class P1,class P2,class P3,class P4,class R>
+ struct CommandRet4 : public CommandBase {
+
+ T*instance;
+ M method;
+ typename GetSimpleTypeT<P1>::type_t p1;
+ typename GetSimpleTypeT<P2>::type_t p2;
+ typename GetSimpleTypeT<P3>::type_t p3;
+ typename GetSimpleTypeT<P4>::type_t p4;
+ R* ret;
+ SyncSemaphore *sync;
+
+ virtual void call() { *ret = (instance->*method)(p1,p2,p3,p4); sync->sem->post(); sync->in_use=false; ; }
+ };
+
+ template<class T,class M,class P1,class P2,class P3,class P4,class P5,class R>
+ struct CommandRet5 : public CommandBase {
+
+ T*instance;
+ M method;
+ typename GetSimpleTypeT<P1>::type_t p1;
+ typename GetSimpleTypeT<P2>::type_t p2;
+ typename GetSimpleTypeT<P3>::type_t p3;
+ typename GetSimpleTypeT<P4>::type_t p4;
+ typename GetSimpleTypeT<P5>::type_t p5;
+ R* ret;
+ SyncSemaphore *sync;
+
+ virtual void call() { *ret = (instance->*method)(p1,p2,p3,p4,p5); sync->sem->post(); sync->in_use=false; ; }
+ };
+
+ template<class T,class M,class P1,class P2,class P3,class P4,class P5,class P6,class R>
+ struct CommandRet6 : public CommandBase {
+
+ T*instance;
+ M method;
+ typename GetSimpleTypeT<P1>::type_t p1;
+ typename GetSimpleTypeT<P2>::type_t p2;
+ typename GetSimpleTypeT<P3>::type_t p3;
+ typename GetSimpleTypeT<P4>::type_t p4;
+ typename GetSimpleTypeT<P5>::type_t p5;
+ typename GetSimpleTypeT<P6>::type_t p6;
+ R* ret;
+ SyncSemaphore *sync;
+
+ virtual void call() { *ret = (instance->*method)(p1,p2,p3,p4,p5,p6); sync->sem->post(); sync->in_use=false; ; }
+ };
+
+ template<class T,class M,class P1,class P2,class P3,class P4,class P5,class P6,class P7,class R>
+ struct CommandRet7 : public CommandBase {
+
+ T*instance;
+ M method;
+ typename GetSimpleTypeT<P1>::type_t p1;
+ typename GetSimpleTypeT<P2>::type_t p2;
+ typename GetSimpleTypeT<P3>::type_t p3;
+ typename GetSimpleTypeT<P4>::type_t p4;
+ typename GetSimpleTypeT<P5>::type_t p5;
+ typename GetSimpleTypeT<P6>::type_t p6;
+ typename GetSimpleTypeT<P7>::type_t p7;
+ R* ret;
+ SyncSemaphore *sync;
+
+ virtual void call() { *ret = (instance->*method)(p1,p2,p3,p4,p5,p6,p7); sync->sem->post(); sync->in_use=false; ; }
+ };
+
+ /** commands that don't return but sync */
+
+ /* comands that return */
+
+ template<class T,class M>
+ struct CommandSync0 : public CommandBase {
+
+ T*instance;
+ M method;
+
+ SyncSemaphore *sync;
+
+ virtual void call() { (instance->*method)(); sync->sem->post(); sync->in_use=false; ; }
+ };
+
+ template<class T,class M,class P1>
+ struct CommandSync1 : public CommandBase {
+
+ T*instance;
+ M method;
+ typename GetSimpleTypeT<P1>::type_t p1;
+
+ SyncSemaphore *sync;
+
+ virtual void call() { (instance->*method)(p1); sync->sem->post(); sync->in_use=false; ; }
+ };
+
+ template<class T,class M,class P1,class P2>
+ struct CommandSync2 : public CommandBase {
+
+ T*instance;
+ M method;
+ typename GetSimpleTypeT<P1>::type_t p1;
+ typename GetSimpleTypeT<P2>::type_t p2;
+
+ SyncSemaphore *sync;
+
+ virtual void call() { (instance->*method)(p1,p2); sync->sem->post(); sync->in_use=false; ; }
+ };
+
+ template<class T,class M,class P1,class P2,class P3>
+ struct CommandSync3 : public CommandBase {
+
+ T*instance;
+ M method;
+ typename GetSimpleTypeT<P1>::type_t p1;
+ typename GetSimpleTypeT<P2>::type_t p2;
+ typename GetSimpleTypeT<P3>::type_t p3;
+
+ SyncSemaphore *sync;
+
+ virtual void call() { (instance->*method)(p1,p2,p3); sync->sem->post(); sync->in_use=false; ; }
+ };
+
+ template<class T,class M,class P1,class P2,class P3,class P4>
+ struct CommandSync4 : public CommandBase {
+
+ T*instance;
+ M method;
+ typename GetSimpleTypeT<P1>::type_t p1;
+ typename GetSimpleTypeT<P2>::type_t p2;
+ typename GetSimpleTypeT<P3>::type_t p3;
+ typename GetSimpleTypeT<P4>::type_t p4;
+
+ SyncSemaphore *sync;
+
+ virtual void call() { (instance->*method)(p1,p2,p3,p4); sync->sem->post(); sync->in_use=false; ; }
+ };
+
+ template<class T,class M,class P1,class P2,class P3,class P4,class P5>
+ struct CommandSync5 : public CommandBase {
+
+ T*instance;
+ M method;
+ typename GetSimpleTypeT<P1>::type_t p1;
+ typename GetSimpleTypeT<P2>::type_t p2;
+ typename GetSimpleTypeT<P3>::type_t p3;
+ typename GetSimpleTypeT<P4>::type_t p4;
+ typename GetSimpleTypeT<P5>::type_t p5;
+
+ SyncSemaphore *sync;
+
+ virtual void call() { (instance->*method)(p1,p2,p3,p4,p5); sync->sem->post(); sync->in_use=false; ; }
+ };
+
+ template<class T,class M,class P1,class P2,class P3,class P4,class P5,class P6>
+ struct CommandSync6 : public CommandBase {
+
+ T*instance;
+ M method;
+ typename GetSimpleTypeT<P1>::type_t p1;
+ typename GetSimpleTypeT<P2>::type_t p2;
+ typename GetSimpleTypeT<P3>::type_t p3;
+ typename GetSimpleTypeT<P4>::type_t p4;
+ typename GetSimpleTypeT<P5>::type_t p5;
+ typename GetSimpleTypeT<P6>::type_t p6;
+
+ SyncSemaphore *sync;
+
+ virtual void call() { (instance->*method)(p1,p2,p3,p4,p5,p6); sync->sem->post(); sync->in_use=false; ; }
+ };
+
+ template<class T,class M,class P1,class P2,class P3,class P4,class P5,class P6,class P7>
+ struct CommandSync7 : public CommandBase {
+
+ T*instance;
+ M method;
+ typename GetSimpleTypeT<P1>::type_t p1;
+ typename GetSimpleTypeT<P2>::type_t p2;
+ typename GetSimpleTypeT<P3>::type_t p3;
+ typename GetSimpleTypeT<P4>::type_t p4;
+ typename GetSimpleTypeT<P5>::type_t p5;
+ typename GetSimpleTypeT<P6>::type_t p6;
+ typename GetSimpleTypeT<P7>::type_t p7;
+
+ SyncSemaphore *sync;
+
+ virtual void call() { (instance->*method)(p1,p2,p3,p4,p5,p6,p7); sync->sem->post(); sync->in_use=false; ; }
+ };
+
+ /***** BASE *******/
+
+ enum {
+ COMMAND_MEM_SIZE_KB=256,
+ COMMAND_MEM_SIZE=COMMAND_MEM_SIZE_KB*1024,
+ SYNC_SEMAPHORES=8
+ };
+
+
+ uint8_t command_mem[COMMAND_MEM_SIZE];
+ uint32_t read_ptr;
+ uint32_t write_ptr;
+ SyncSemaphore sync_sems[SYNC_SEMAPHORES];
+ Mutex *mutex;
+ Semaphore *sync;
+
+
+ template<class T>
+ T* allocate() {
+
+ // alloc size is size+T+safeguard
+ uint32_t alloc_size=sizeof(T)+sizeof(uint32_t);
+
+ tryagain:
+
+ if (write_ptr < read_ptr) {
+ // behind read_ptr, check that there is room
+ if ( (read_ptr-write_ptr) <= alloc_size )
+ return NULL;
+ } else if (write_ptr >= read_ptr) {
+ // ahead of read_ptr, check that there is room
+
+
+ if ( (COMMAND_MEM_SIZE-write_ptr) < alloc_size+4 ) {
+ // no room at the end, wrap down;
+
+ if (read_ptr==0) // dont want write_ptr to become read_ptr
+ return NULL;
+
+ // if this happens, it's a bug
+ ERR_FAIL_COND_V( (COMMAND_MEM_SIZE-write_ptr) < sizeof(uint32_t), NULL );
+ // zero means, wrap to begining
+
+ uint32_t * p = (uint32_t*)&command_mem[write_ptr];
+ *p=0;
+ write_ptr=0;
+ goto tryagain;
+ }
+ }
+ // allocate the size
+ uint32_t * p = (uint32_t*)&command_mem[write_ptr];
+ *p=sizeof(T);
+ write_ptr+=sizeof(uint32_t);
+ // allocate the command
+ T* cmd = memnew_placement( &command_mem[write_ptr], T );
+ write_ptr+=sizeof(T);
+ return cmd;
+
+ }
+
+ template<class T>
+ T* allocate_and_lock() {
+
+ lock();
+ T* ret;
+
+ while ( (ret=allocate<T>())==NULL ) {
+
+ unlock();
+ // sleep a little until fetch happened and some room is made
+ wait_for_flush();
+ lock();
+
+ }
+
+ return ret;
+ }
+
+
+ bool flush_one() {
+
+ tryagain:
+
+ // tried to read an empty queue
+ if (read_ptr == write_ptr )
+ return false;
+
+ uint32_t size = *(uint32_t*)( &command_mem[read_ptr] );
+
+ if (size==0) {
+ //end of ringbuffer, wrap
+ read_ptr=0;
+ goto tryagain;
+ }
+
+ read_ptr+=sizeof(uint32_t);
+
+ CommandBase *cmd = reinterpret_cast<CommandBase*>( &command_mem[read_ptr] );
+
+ cmd->call();
+ cmd->~CommandBase();
+
+ read_ptr+=size;
+
+ return true;
+ }
+
+
+ void lock();
+ void unlock();
+ void wait_for_flush();
+ SyncSemaphore* _alloc_sync_sem();
+
+
+public:
+
+ /* NORMAL PUSH COMMANDS */
+
+ template<class T, class M>
+ void push( T * p_instance, M p_method ) {
+
+ Command0<T,M> * cmd = allocate_and_lock< Command0<T,M> >();
+
+ cmd->instance=p_instance;
+ cmd->method=p_method;
+
+ unlock();
+
+ if (sync) sync->post();
+ }
+
+ template<class T, class M, class P1>
+ void push( T * p_instance, M p_method, P1 p1 ) {
+
+ Command1<T,M,P1> * cmd = allocate_and_lock< Command1<T,M,P1> >();
+
+ cmd->instance=p_instance;
+ cmd->method=p_method;
+ cmd->p1=p1;
+
+ unlock();
+
+ if (sync) sync->post();
+ }
+
+ template<class T, class M, class P1, class P2>
+ void push( T * p_instance, M p_method, P1 p1, P2 p2 ) {
+
+ Command2<T,M,P1,P2> * cmd = allocate_and_lock< Command2<T,M,P1,P2> >();
+
+ cmd->instance=p_instance;
+ cmd->method=p_method;
+ cmd->p1=p1;
+ cmd->p2=p2;
+
+ unlock();
+
+ if (sync) sync->post();
+ }
+
+ template<class T, class M, class P1, class P2, class P3>
+ void push( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3 ) {
+
+ Command3<T,M,P1,P2,P3> * cmd = allocate_and_lock< Command3<T,M,P1,P2,P3> >();
+
+ cmd->instance=p_instance;
+ cmd->method=p_method;
+ cmd->p1=p1;
+ cmd->p2=p2;
+ cmd->p3=p3;
+
+ unlock();
+
+ if (sync) sync->post();
+ }
+
+ template<class T, class M, class P1, class P2, class P3, class P4>
+ void push( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3, P4 p4 ) {
+
+ Command4<T,M,P1,P2,P3,P4> * cmd = allocate_and_lock< Command4<T,M,P1,P2,P3,P4> >();
+
+ cmd->instance=p_instance;
+ cmd->method=p_method;
+ cmd->p1=p1;
+ cmd->p2=p2;
+ cmd->p3=p3;
+ cmd->p4=p4;
+
+ unlock();
+
+ if (sync) sync->post();
+ }
+
+ template<class T, class M, class P1, class P2, class P3, class P4, class P5>
+ void push( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5 ) {
+
+ Command5<T,M,P1,P2,P3,P4,P5> * cmd = allocate_and_lock< Command5<T,M,P1,P2,P3,P4,P5> >();
+
+ cmd->instance=p_instance;
+ cmd->method=p_method;
+ cmd->p1=p1;
+ cmd->p2=p2;
+ cmd->p3=p3;
+ cmd->p4=p4;
+ cmd->p5=p5;
+
+ unlock();
+
+ if (sync) sync->post();
+ }
+
+ template<class T, class M, class P1, class P2, class P3, class P4, class P5, class P6>
+ void push( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6 ) {
+
+ Command6<T,M,P1,P2,P3,P4,P5,P6> * cmd = allocate_and_lock< Command6<T,M,P1,P2,P3,P4,P5,P6> >();
+
+ cmd->instance=p_instance;
+ cmd->method=p_method;
+ cmd->p1=p1;
+ cmd->p2=p2;
+ cmd->p3=p3;
+ cmd->p4=p4;
+ cmd->p5=p5;
+ cmd->p6=p6;
+
+ unlock();
+
+ if (sync) sync->post();
+ }
+
+ template<class T, class M, class P1, class P2, class P3, class P4, class P5, class P6, class P7>
+ void push( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7 ) {
+
+ Command7<T,M,P1,P2,P3,P4,P5,P6,P7> * cmd = allocate_and_lock< Command7<T,M,P1,P2,P3,P4,P5,P6,P7> >();
+
+ cmd->instance=p_instance;
+ cmd->method=p_method;
+ cmd->p1=p1;
+ cmd->p2=p2;
+ cmd->p3=p3;
+ cmd->p4=p4;
+ cmd->p5=p5;
+ cmd->p6=p6;
+ cmd->p7=p7;
+
+ unlock();
+
+ if (sync) sync->post();
+ }
+ /*** PUSH AND RET COMMANDS ***/
+
+
+ template<class T, class M,class R>
+ void push_and_ret( T * p_instance, M p_method, R* r_ret) {
+
+ CommandRet0<T,M,R> * cmd = allocate_and_lock< CommandRet0<T,M,R> >();
+
+ cmd->instance=p_instance;
+ cmd->method=p_method;
+ cmd->ret=r_ret;
+ SyncSemaphore *ss=_alloc_sync_sem();
+ cmd->sync=ss;
+
+ unlock();
+
+ if (sync) sync->post();
+ ss->sem->wait();
+ }
+
+ template<class T, class M, class P1,class R>
+ void push_and_ret( T * p_instance, M p_method, P1 p1, R* r_ret) {
+
+ CommandRet1<T,M,P1,R> * cmd = allocate_and_lock< CommandRet1<T,M,P1,R> >();
+
+ cmd->instance=p_instance;
+ cmd->method=p_method;
+ cmd->p1=p1;
+ cmd->ret=r_ret;
+ SyncSemaphore *ss=_alloc_sync_sem();
+ cmd->sync=ss;
+
+ unlock();
+
+ if (sync) sync->post();
+ ss->sem->wait();
+ }
+
+ template<class T, class M, class P1, class P2,class R>
+ void push_and_ret( T * p_instance, M p_method, P1 p1, P2 p2, R* r_ret) {
+
+ CommandRet2<T,M,P1,P2,R> * cmd = allocate_and_lock< CommandRet2<T,M,P1,P2,R> >();
+
+ cmd->instance=p_instance;
+ cmd->method=p_method;
+ cmd->p1=p1;
+ cmd->p2=p2;
+ cmd->ret=r_ret;
+ SyncSemaphore *ss=_alloc_sync_sem();
+ cmd->sync=ss;
+
+ unlock();
+
+ if (sync) sync->post();
+ ss->sem->wait();
+ }
+
+ template<class T, class M, class P1, class P2, class P3,class R>
+ void push_and_ret( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3, R* r_ret ) {
+
+ CommandRet3<T,M,P1,P2,P3,R> * cmd = allocate_and_lock< CommandRet3<T,M,P1,P2,P3,R> >();
+
+ cmd->instance=p_instance;
+ cmd->method=p_method;
+ cmd->p1=p1;
+ cmd->p2=p2;
+ cmd->p3=p3;
+ cmd->ret=r_ret;
+ SyncSemaphore *ss=_alloc_sync_sem();
+ cmd->sync=ss;
+
+ unlock();
+
+ if (sync) sync->post();
+ ss->sem->wait();
+ }
+
+ template<class T, class M, class P1, class P2, class P3, class P4,class R>
+ void push_and_ret( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3, P4 p4, R* r_ret ) {
+
+ CommandRet4<T,M,P1,P2,P3,P4,R> * cmd = allocate_and_lock< CommandRet4<T,M,P1,P2,P3,P4,R> >();
+
+ cmd->instance=p_instance;
+ cmd->method=p_method;
+ cmd->p1=p1;
+ cmd->p2=p2;
+ cmd->p3=p3;
+ cmd->p4=p4;
+ cmd->ret=r_ret;
+ SyncSemaphore *ss=_alloc_sync_sem();
+ cmd->sync=ss;
+
+ unlock();
+
+ if (sync) sync->post();
+ ss->sem->wait();
+ }
+
+ template<class T, class M, class P1, class P2, class P3, class P4, class P5,class R>
+ void push_and_ret( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, R* r_ret ) {
+
+ CommandRet5<T,M,P1,P2,P3,P4,P5,R> * cmd = allocate_and_lock< CommandRet5<T,M,P1,P2,P3,P4,P5,R> >();
+
+ cmd->instance=p_instance;
+ cmd->method=p_method;
+ cmd->p1=p1;
+ cmd->p2=p2;
+ cmd->p3=p3;
+ cmd->p4=p4;
+ cmd->p5=p5;
+ cmd->ret=r_ret;
+ SyncSemaphore *ss=_alloc_sync_sem();
+ cmd->sync=ss;
+
+ unlock();
+
+ if (sync) sync->post();
+ ss->sem->wait();
+ }
+
+ template<class T, class M, class P1, class P2, class P3, class P4, class P5, class P6,class R>
+ void push_and_ret( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, R* r_ret ) {
+
+ CommandRet6<T,M,P1,P2,P3,P4,P5,P6,R> * cmd = allocate_and_lock< CommandRet6<T,M,P1,P2,P3,P4,P5,P6,R> >();
+
+ cmd->instance=p_instance;
+ cmd->method=p_method;
+ cmd->p1=p1;
+ cmd->p2=p2;
+ cmd->p3=p3;
+ cmd->p4=p4;
+ cmd->p5=p5;
+ cmd->p6=p6;
+ cmd->ret=r_ret;
+ SyncSemaphore *ss=_alloc_sync_sem();
+ cmd->sync=ss;
+
+ unlock();
+
+ if (sync) sync->post();
+ ss->sem->wait();
+ }
+
+ template<class T, class M, class P1, class P2, class P3, class P4, class P5, class P6,class P7,class R>
+ void push_and_ret( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6,P7 p7, R* r_ret ) {
+
+ CommandRet7<T,M,P1,P2,P3,P4,P5,P6,P7,R> * cmd = allocate_and_lock< CommandRet7<T,M,P1,P2,P3,P4,P5,P6,P7,R> >();
+
+ cmd->instance=p_instance;
+ cmd->method=p_method;
+ cmd->p1=p1;
+ cmd->p2=p2;
+ cmd->p3=p3;
+ cmd->p4=p4;
+ cmd->p5=p5;
+ cmd->p6=p6;
+ cmd->p7=p7;
+ cmd->ret=r_ret;
+ SyncSemaphore *ss=_alloc_sync_sem();
+ cmd->sync=ss;
+
+ unlock();
+
+ if (sync) sync->post();
+ ss->sem->wait();
+ }
+
+
+ template<class T, class M>
+ void push_and_sync( T * p_instance, M p_method) {
+
+ CommandSync0<T,M> * cmd = allocate_and_lock< CommandSync0<T,M> >();
+
+ cmd->instance=p_instance;
+ cmd->method=p_method;
+
+ SyncSemaphore *ss=_alloc_sync_sem();
+ cmd->sync=ss;
+
+ unlock();
+
+ if (sync) sync->post();
+ ss->sem->wait();
+ }
+
+ template<class T, class M, class P1>
+ void push_and_sync( T * p_instance, M p_method, P1 p1) {
+
+ CommandSync1<T,M,P1> * cmd = allocate_and_lock< CommandSync1<T,M,P1> >();
+
+ cmd->instance=p_instance;
+ cmd->method=p_method;
+ cmd->p1=p1;
+
+ SyncSemaphore *ss=_alloc_sync_sem();
+ cmd->sync=ss;
+
+ unlock();
+
+ if (sync) sync->post();
+ ss->sem->wait();
+ }
+
+ template<class T, class M, class P1, class P2>
+ void push_and_sync( T * p_instance, M p_method, P1 p1, P2 p2) {
+
+ CommandSync2<T,M,P1,P2> * cmd = allocate_and_lock< CommandSync2<T,M,P1,P2> >();
+
+ cmd->instance=p_instance;
+ cmd->method=p_method;
+ cmd->p1=p1;
+ cmd->p2=p2;
+
+ SyncSemaphore *ss=_alloc_sync_sem();
+ cmd->sync=ss;
+
+ unlock();
+
+ if (sync) sync->post();
+ ss->sem->wait();
+ }
+
+ template<class T, class M, class P1, class P2, class P3>
+ void push_and_sync( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3 ) {
+
+ CommandSync3<T,M,P1,P2,P3> * cmd = allocate_and_lock< CommandSync3<T,M,P1,P2,P3> >();
+
+ cmd->instance=p_instance;
+ cmd->method=p_method;
+ cmd->p1=p1;
+ cmd->p2=p2;
+ cmd->p3=p3;
+
+ SyncSemaphore *ss=_alloc_sync_sem();
+ cmd->sync=ss;
+
+ unlock();
+
+ if (sync) sync->post();
+ ss->sem->wait();
+ }
+
+ template<class T, class M, class P1, class P2, class P3, class P4>
+ void push_and_sync( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3, P4 p4 ) {
+
+ CommandSync4<T,M,P1,P2,P3,P4> * cmd = allocate_and_lock< CommandSync4<T,M,P1,P2,P3,P4> >();
+
+ cmd->instance=p_instance;
+ cmd->method=p_method;
+ cmd->p1=p1;
+ cmd->p2=p2;
+ cmd->p3=p3;
+ cmd->p4=p4;
+
+ SyncSemaphore *ss=_alloc_sync_sem();
+ cmd->sync=ss;
+
+ unlock();
+
+ if (sync) sync->post();
+ ss->sem->wait();
+ }
+
+ template<class T, class M, class P1, class P2, class P3, class P4, class P5>
+ void push_and_sync( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5 ) {
+
+ CommandSync5<T,M,P1,P2,P3,P4,P5> * cmd = allocate_and_lock< CommandSync5<T,M,P1,P2,P3,P4,P5> >();
+
+ cmd->instance=p_instance;
+ cmd->method=p_method;
+ cmd->p1=p1;
+ cmd->p2=p2;
+ cmd->p3=p3;
+ cmd->p4=p4;
+ cmd->p5=p5;
+
+ SyncSemaphore *ss=_alloc_sync_sem();
+ cmd->sync=ss;
+
+ unlock();
+
+ if (sync) sync->post();
+ ss->sem->wait();
+ }
+
+ template<class T, class M, class P1, class P2, class P3, class P4, class P5, class P6>
+ void push_and_sync( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6 ) {
+
+ CommandSync6<T,M,P1,P2,P3,P4,P5,P6> * cmd = allocate_and_lock< CommandSync6<T,M,P1,P2,P3,P4,P5,P6> >();
+
+ cmd->instance=p_instance;
+ cmd->method=p_method;
+ cmd->p1=p1;
+ cmd->p2=p2;
+ cmd->p3=p3;
+ cmd->p4=p4;
+ cmd->p5=p5;
+ cmd->p6=p6;
+
+ SyncSemaphore *ss=_alloc_sync_sem();
+ cmd->sync=ss;
+
+ unlock();
+
+ if (sync) sync->post();
+ ss->sem->wait();
+ }
+
+ template<class T, class M, class P1, class P2, class P3, class P4, class P5, class P6,class P7>
+ void push_and_sync( T * p_instance, M p_method, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6,P7 p7 ) {
+
+ CommandSync7<T,M,P1,P2,P3,P4,P5,P6,P7> * cmd = allocate_and_lock< CommandSync7<T,M,P1,P2,P3,P4,P5,P6,P7> >();
+
+ cmd->instance=p_instance;
+ cmd->method=p_method;
+ cmd->p1=p1;
+ cmd->p2=p2;
+ cmd->p3=p3;
+ cmd->p4=p4;
+ cmd->p5=p5;
+ cmd->p6=p6;
+ cmd->p7=p7;
+
+ SyncSemaphore *ss=_alloc_sync_sem();
+ cmd->sync=ss;
+
+ unlock();
+
+ if (sync) sync->post();
+ ss->sem->wait();
+ }
+
+ void wait_and_flush_one() {
+ ERR_FAIL_COND(!sync);
+ sync->wait();
+ lock();
+ flush_one();
+ unlock();
+ }
+
+ void flush_all() {
+
+ ERR_FAIL_COND(sync);
+ lock();
+ while (true) {
+ bool exit = !flush_one();
+ if (exit)
+ break;
+ }
+ unlock();
+ }
+
+ CommandQueueMT(bool p_sync);
+ ~CommandQueueMT();
+
+};
+
+#endif