diff --git a/SCsub b/SCsub index ffdb429..63928fc 100644 --- a/SCsub +++ b/SCsub @@ -10,6 +10,7 @@ sources = [ "thread_pool.cpp", "thread_pool_job.cpp", + "thread_pool_execute_job.cpp", ] if ARGUMENTS.get('custom_modules_shared', 'no') == 'yes': diff --git a/config.py b/config.py index 0db1cb6..edf69f0 100644 --- a/config.py +++ b/config.py @@ -33,6 +33,7 @@ def get_doc_classes(): return [ "ThreadPool", "ThreadPoolJob", + "ThreadPoolExecuteJob", ] def get_doc_path(): diff --git a/register_types.cpp b/register_types.cpp index 62862a7..f5bd197 100644 --- a/register_types.cpp +++ b/register_types.cpp @@ -27,6 +27,7 @@ SOFTWARE. #include "core/engine.h" #include "thread_pool.h" +#include "thread_pool_execute_job.h" #include "thread_pool_job.h" static ThreadPool *thread_pool = NULL; @@ -34,6 +35,7 @@ static ThreadPool *thread_pool = NULL; void register_thread_pool_types() { ClassDB::register_class(); + ClassDB::register_class(); thread_pool = memnew(ThreadPool); ClassDB::register_class(); diff --git a/thread_pool.cpp b/thread_pool.cpp index 3d54613..78d3694 100644 --- a/thread_pool.cpp +++ b/thread_pool.cpp @@ -199,8 +199,8 @@ void ThreadPool::add_job(const Ref &job) { _queue.write[_current_queue_tail] = job; } -Ref ThreadPool::create_job_simple(const Variant &obj, const StringName &p_method) { - Ref job; +Ref ThreadPool::create_execute_job_simple(const Variant &obj, const StringName &p_method) { + Ref job; job.instance(); job->setup(obj, p_method); @@ -212,8 +212,8 @@ Ref ThreadPool::create_job_simple(const Variant &obj, const Strin return job; } -Ref ThreadPool::create_job(const Variant &obj, const StringName &p_method, VARIANT_ARG_DECLARE) { - Ref job; +Ref ThreadPool::create_execute_job(const Variant &obj, const StringName &p_method, VARIANT_ARG_DECLARE) { + Ref job; job.instance(); job->setup(obj, p_method, p_arg1, p_arg2, p_arg3, p_arg4, p_arg5); @@ -265,7 +265,7 @@ Variant ThreadPool::_create_job_bind(const Variant **p_args, int p_argcount, Cal return Variant(); } - Ref job; + Ref job; job.instance(); job->_setup_bind(p_args, p_argcount, r_error); @@ -415,14 +415,14 @@ void ThreadPool::_bind_methods() { ClassDB::bind_method(D_METHOD("set_max_time_per_frame", "value"), &ThreadPool::set_max_time_per_frame); ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_time_per_frame"), "set_max_time_per_frame", "get_max_time_per_frame"); - ClassDB::bind_method(D_METHOD("create_job_simple", "object", "method"), &ThreadPool::create_job_simple); + ClassDB::bind_method(D_METHOD("create_execute_job_simple", "object", "method"), &ThreadPool::create_execute_job_simple); MethodInfo mi; mi.arguments.push_back(PropertyInfo(Variant::OBJECT, "obj")); mi.arguments.push_back(PropertyInfo(Variant::STRING, "method")); mi.name = "create_job"; - ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "create_job", &ThreadPool::_create_job_bind, mi); + ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "create_execute_job", &ThreadPool::_create_job_bind, mi); ClassDB::bind_method(D_METHOD("get_running_job", "object", "method"), &ThreadPool::get_running_job); ClassDB::bind_method(D_METHOD("get_queued_job", "object", "method"), &ThreadPool::get_queued_job); diff --git a/thread_pool.h b/thread_pool.h index a4eba56..8964127 100644 --- a/thread_pool.h +++ b/thread_pool.h @@ -32,6 +32,7 @@ SOFTWARE. #include "core/os/thread_safe.h" #include "core/vector.h" #include "core/version.h" +#include "thread_pool_execute_job.h" #include "thread_pool_job.h" class ThreadPool : public Object { @@ -76,9 +77,8 @@ public: void add_job(const Ref &job); - Ref create_job_simple(const Variant &object, const StringName &method); - - Ref create_job(const Variant &object, const StringName &method, VARIANT_ARG_LIST); + Ref create_execute_job_simple(const Variant &object, const StringName &method); + Ref create_execute_job(const Variant &object, const StringName &method, VARIANT_ARG_LIST); #if VERSION_MAJOR < 4 Variant _create_job_bind(const Variant **p_args, int p_argcount, Variant::CallError &r_error); #else diff --git a/thread_pool_execute_job.cpp b/thread_pool_execute_job.cpp new file mode 100644 index 0000000..56a15cf --- /dev/null +++ b/thread_pool_execute_job.cpp @@ -0,0 +1,185 @@ +/* +Copyright (c) 2019-2020 Péter Magyar + +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. +*/ + +#include "thread_pool_execute_job.h" + +#include "core/os/os.h" +#include "core/variant.h" + +Variant ThreadPoolExecuteJob::get_object() const { + return _object; +} +void ThreadPoolExecuteJob::set_object(const Variant &value) { + _object = value; +} + +StringName ThreadPoolExecuteJob::get_method() const { + return _method; +} +void ThreadPoolExecuteJob::set_method(const StringName &value) { + _method = value; +} + +void ThreadPoolExecuteJob::_execute() { + ERR_FAIL_COND(!_object); + ERR_FAIL_COND(!_object->has_method(_method)); + + set_current_run_stage(0); + set_start_time(OS::get_singleton()->get_system_time_msecs()); + + Variant::CallError error; + + _object->call(_method, const_cast(&_argptr), _argcount, error); +} + +void ThreadPoolExecuteJob::setup(const Variant &obj, const StringName &p_method, VARIANT_ARG_DECLARE) { + set_complete(false); + set_cancelled(false); + _object = obj; + _method = p_method; + + _argptr[0] = p_arg1; + _argptr[1] = p_arg2; + _argptr[2] = p_arg3; + _argptr[3] = p_arg4; + _argptr[4] = p_arg5; + + for (int i = 4; i >= 0; --i) { + if (_argptr[i].get_type() != Variant::NIL) { + _argcount = i + 1; + break; + } + } + + if (!_object || !_object->has_method(p_method)) { + set_complete(true); + + ERR_FAIL_COND(!_object); + ERR_FAIL_COND(!_object->has_method(p_method)); + } +} + +#if VERSION_MAJOR < 4 +Variant ThreadPoolExecuteJob::_setup_bind(const Variant **p_args, int p_argcount, Variant::CallError &r_error) { +#else +Variant ThreadPoolExecuteJob::_setup_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { +#endif + if (p_argcount < 2) { +#if VERSION_MAJOR < 4 + r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; +#else + r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; +#endif + + r_error.argument = 1; + return Variant(); + } + + if (p_args[0]->get_type() != Variant::OBJECT) { +#if VERSION_MAJOR < 4 + r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; +#else + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; +#endif + + r_error.argument = 0; + r_error.expected = Variant::OBJECT; + return Variant(); + } + + if (p_args[1]->get_type() != Variant::STRING) { +#if VERSION_MAJOR < 4 + r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; +#else + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; +#endif + + r_error.argument = 1; + r_error.expected = Variant::STRING; + return Variant(); + } + + set_complete(false); + _object = *p_args[0]; + + StringName sn = *p_args[1]; + _method = sn; + + if (p_argcount > 2) { + _argcount = 1; + _argptr[0] = p_args[2]; + } + + if (p_argcount > 3) { + _argcount = 2; + _argptr[1] = p_args[3]; + } + + if (p_argcount > 4) { + _argcount = 3; + _argptr[2] = p_args[4]; + } + + if (p_argcount > 5) { + _argcount = 4; + _argptr[3] = p_args[5]; + } + + if (p_argcount > 6) { + _argcount = 5; + _argptr[4] = p_args[6]; + } + + if (!_object || !_object->has_method(_method)) { + set_complete(true); + } + +#if VERSION_MAJOR < 4 + r_error.error = Variant::CallError::CALL_OK; +#else + r_error.error = Callable::CallError::CALL_OK; +#endif + + return Variant(); +} + +ThreadPoolExecuteJob::ThreadPoolExecuteJob() { + _object = NULL; + + _argcount = 0; + + _argptr = memnew_arr(Variant, 5); +} +ThreadPoolExecuteJob::~ThreadPoolExecuteJob() { + memdelete_arr(_argptr); +} + +void ThreadPoolExecuteJob::_bind_methods() { + ClassDB::bind_method(D_METHOD("_execute"), &ThreadPoolExecuteJob::_execute); + + MethodInfo mi; + mi.arguments.push_back(PropertyInfo(Variant::OBJECT, "obj")); + mi.arguments.push_back(PropertyInfo(Variant::STRING, "method")); + + mi.name = "setup"; + ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "setup", &ThreadPoolExecuteJob::_setup_bind, mi); +} diff --git a/thread_pool_execute_job.h b/thread_pool_execute_job.h new file mode 100644 index 0000000..1f405ca --- /dev/null +++ b/thread_pool_execute_job.h @@ -0,0 +1,59 @@ +/* +Copyright (c) 2019-2020 Péter Magyar + +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 THREAD_POOL_EXECUTE_JOB_H +#define THREAD_POOL_EXECUTE_JOB_H + +#include "thread_pool_job.h" + +class ThreadPoolExecuteJob : public ThreadPoolJob { + GDCLASS(ThreadPoolExecuteJob, ThreadPoolJob); + +public: + Variant get_object() const; + void set_object(const Variant &value); + + StringName get_method() const; + void set_method(const StringName &value); + + void _execute(); + void setup(const Variant &obj, const StringName &p_method, VARIANT_ARG_LIST); +#if VERSION_MAJOR < 4 + Variant _setup_bind(const Variant **p_args, int p_argcount, Variant::CallError &r_error); +#else + Variant _setup_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error); +#endif + + ThreadPoolExecuteJob(); + ~ThreadPoolExecuteJob(); + +protected: + static void _bind_methods(); + +private: + Object *_object; + StringName _method; + int _argcount; + Variant *_argptr; +}; + +#endif diff --git a/thread_pool_job.cpp b/thread_pool_job.cpp index c810da2..75b3a30 100644 --- a/thread_pool_job.cpp +++ b/thread_pool_job.cpp @@ -118,126 +118,9 @@ bool ThreadPoolJob::should_return() { } void ThreadPoolJob::execute() { - ERR_FAIL_COND(!_object); - ERR_FAIL_COND(!_object->has_method(_method)); + ERR_FAIL_COND(!has_method("_execute")); - _current_run_stage = 0; - _start_time = OS::get_singleton()->get_system_time_msecs(); - - Variant::CallError error; - - _object->call(_method, const_cast(&_argptr), _argcount, error); -} - -void ThreadPoolJob::setup(const Variant &obj, const StringName &p_method, VARIANT_ARG_DECLARE) { - _complete = false; - _cancelled = false; - _object = obj; - _method = p_method; - - _argptr[0] = p_arg1; - _argptr[1] = p_arg2; - _argptr[2] = p_arg3; - _argptr[3] = p_arg4; - _argptr[4] = p_arg5; - - for (int i = 4; i >= 0; --i) { - if (_argptr[i].get_type() != Variant::NIL) { - _argcount = i + 1; - break; - } - } - - if (!_object || !_object->has_method(p_method)) { - _complete = true; - - ERR_FAIL_COND(!_object); - ERR_FAIL_COND(!_object->has_method(p_method)); - } -} - -#if VERSION_MAJOR < 4 -Variant ThreadPoolJob::_setup_bind(const Variant **p_args, int p_argcount, Variant::CallError &r_error) { -#else -Variant ThreadPoolJob::_setup_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { -#endif - if (p_argcount < 2) { -#if VERSION_MAJOR < 4 - r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; -#else - r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; -#endif - - r_error.argument = 1; - return Variant(); - } - - if (p_args[0]->get_type() != Variant::OBJECT) { -#if VERSION_MAJOR < 4 - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; -#else - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; -#endif - - r_error.argument = 0; - r_error.expected = Variant::OBJECT; - return Variant(); - } - - if (p_args[1]->get_type() != Variant::STRING) { -#if VERSION_MAJOR < 4 - r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; -#else - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; -#endif - - r_error.argument = 1; - r_error.expected = Variant::STRING; - return Variant(); - } - - _complete = false; - _object = *p_args[0]; - - StringName sn = *p_args[1]; - _method = sn; - - if (p_argcount > 2) { - _argcount = 1; - _argptr[0] = p_args[2]; - } - - if (p_argcount > 3) { - _argcount = 2; - _argptr[1] = p_args[3]; - } - - if (p_argcount > 4) { - _argcount = 3; - _argptr[2] = p_args[4]; - } - - if (p_argcount > 5) { - _argcount = 4; - _argptr[3] = p_args[5]; - } - - if (p_argcount > 6) { - _argcount = 5; - _argptr[4] = p_args[6]; - } - - if (!_object || !_object->has_method(_method)) { - _complete = true; - } - -#if VERSION_MAJOR < 4 - r_error.error = Variant::CallError::CALL_OK; -#else - r_error.error = Callable::CallError::CALL_OK; -#endif - - return Variant(); + call("_execute"); } ThreadPoolJob::ThreadPoolJob() { @@ -287,12 +170,6 @@ void ThreadPoolJob::_bind_methods() { ClassDB::bind_method(D_METHOD("should_do", "just_check"), &ThreadPoolJob::should_do, DEFVAL(false)); ClassDB::bind_method(D_METHOD("should_return"), &ThreadPoolJob::should_return); + BIND_VMETHOD(MethodInfo("_execute")); ClassDB::bind_method(D_METHOD("execute"), &ThreadPoolJob::execute); - - MethodInfo mi; - mi.arguments.push_back(PropertyInfo(Variant::OBJECT, "obj")); - mi.arguments.push_back(PropertyInfo(Variant::STRING, "method")); - - mi.name = "setup"; - ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "setup", &ThreadPoolJob::_setup_bind, mi); } diff --git a/thread_pool_job.h b/thread_pool_job.h index 54ce456..f3253f2 100644 --- a/thread_pool_job.h +++ b/thread_pool_job.h @@ -64,12 +64,6 @@ public: bool should_return(); void execute(); - void setup(const Variant &obj, const StringName &p_method, VARIANT_ARG_LIST); -#if VERSION_MAJOR < 4 - Variant _setup_bind(const Variant **p_args, int p_argcount, Variant::CallError &r_error); -#else - Variant _setup_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error); -#endif ThreadPoolJob(); ~ThreadPoolJob();