1 /*************************************************************************/
2 /* thread_jandroid.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
10 /* */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the */
13 /* "Software"), to deal in the Software without restriction, including */
14 /* without limitation the rights to use, copy, modify, merge, publish, */
15 /* distribute, sublicense, and/or sell copies of the Software, and to */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions: */
18 /* */
19 /* The above copyright notice and this permission notice shall be */
20 /* included in all copies or substantial portions of the Software. */
21 /* */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29 /*************************************************************************/
30
31 #include "thread_jandroid.h"
32
33 #include "core/os/memory.h"
34 #include "core/safe_refcount.h"
35 #include "core/script_language.h"
36
_thread_id_key_destr_callback(void * p_value)37 static void _thread_id_key_destr_callback(void *p_value) {
38 memdelete(static_cast<Thread::ID *>(p_value));
39 }
40
_create_thread_id_key()41 static pthread_key_t _create_thread_id_key() {
42 pthread_key_t key;
43 pthread_key_create(&key, &_thread_id_key_destr_callback);
44 return key;
45 }
46
47 pthread_key_t ThreadAndroid::thread_id_key = _create_thread_id_key();
48 Thread::ID ThreadAndroid::next_thread_id = 0;
49
get_id() const50 Thread::ID ThreadAndroid::get_id() const {
51
52 return id;
53 }
54
create_thread_jandroid()55 Thread *ThreadAndroid::create_thread_jandroid() {
56
57 return memnew(ThreadAndroid);
58 }
59
thread_callback(void * userdata)60 void *ThreadAndroid::thread_callback(void *userdata) {
61
62 ThreadAndroid *t = reinterpret_cast<ThreadAndroid *>(userdata);
63 setup_thread();
64 ScriptServer::thread_enter(); //scripts may need to attach a stack
65 t->id = atomic_increment(&next_thread_id);
66 pthread_setspecific(thread_id_key, (void *)memnew(ID(t->id)));
67 t->callback(t->user);
68 ScriptServer::thread_exit();
69 return NULL;
70 }
71
create_func_jandroid(ThreadCreateCallback p_callback,void * p_user,const Settings &)72 Thread *ThreadAndroid::create_func_jandroid(ThreadCreateCallback p_callback, void *p_user, const Settings &) {
73
74 ThreadAndroid *tr = memnew(ThreadAndroid);
75 tr->callback = p_callback;
76 tr->user = p_user;
77 pthread_attr_init(&tr->pthread_attr);
78 pthread_attr_setdetachstate(&tr->pthread_attr, PTHREAD_CREATE_JOINABLE);
79
80 pthread_create(&tr->pthread, &tr->pthread_attr, thread_callback, tr);
81
82 return tr;
83 }
84
get_thread_id_func_jandroid()85 Thread::ID ThreadAndroid::get_thread_id_func_jandroid() {
86
87 void *value = pthread_getspecific(thread_id_key);
88
89 if (value)
90 return *static_cast<ID *>(value);
91
92 ID new_id = atomic_increment(&next_thread_id);
93 pthread_setspecific(thread_id_key, (void *)memnew(ID(new_id)));
94 return new_id;
95 }
96
wait_to_finish_func_jandroid(Thread * p_thread)97 void ThreadAndroid::wait_to_finish_func_jandroid(Thread *p_thread) {
98
99 ThreadAndroid *tp = static_cast<ThreadAndroid *>(p_thread);
100 ERR_FAIL_COND(!tp);
101 ERR_FAIL_COND(tp->pthread == 0);
102
103 pthread_join(tp->pthread, NULL);
104 tp->pthread = 0;
105 }
106
_thread_destroyed(void * value)107 void ThreadAndroid::_thread_destroyed(void *value) {
108
109 /* The thread is being destroyed, detach it from the Java VM and set the mThreadKey value to NULL as required */
110 JNIEnv *env = (JNIEnv *)value;
111 if (env != NULL) {
112 java_vm->DetachCurrentThread();
113 pthread_setspecific(jvm_key, NULL);
114 }
115 }
116
117 pthread_key_t ThreadAndroid::jvm_key;
118 JavaVM *ThreadAndroid::java_vm = NULL;
119
setup_thread()120 void ThreadAndroid::setup_thread() {
121
122 if (pthread_getspecific(jvm_key))
123 return; //already setup
124 JNIEnv *env;
125 java_vm->AttachCurrentThread(&env, NULL);
126 pthread_setspecific(jvm_key, (void *)env);
127 }
128
make_default(JavaVM * p_java_vm)129 void ThreadAndroid::make_default(JavaVM *p_java_vm) {
130
131 java_vm = p_java_vm;
132 create_func = create_func_jandroid;
133 get_thread_id_func = get_thread_id_func_jandroid;
134 wait_to_finish_func = wait_to_finish_func_jandroid;
135 pthread_key_create(&jvm_key, _thread_destroyed);
136 setup_thread();
137 }
138
get_env()139 JNIEnv *ThreadAndroid::get_env() {
140
141 if (!pthread_getspecific(jvm_key)) {
142 setup_thread();
143 }
144
145 JNIEnv *env = NULL;
146 java_vm->AttachCurrentThread(&env, NULL);
147 return env;
148 }
149
ThreadAndroid()150 ThreadAndroid::ThreadAndroid() {
151
152 pthread = 0;
153 }
154
~ThreadAndroid()155 ThreadAndroid::~ThreadAndroid() {
156 }
157