1 /* Copyright (c) 2000, 2021, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 Without limiting anything contained in the foregoing, this file,
15 which is part of C Driver for MySQL (Connector/C), is also subject to the
16 Universal FOSS Exception, version 1.0, a copy of which can be found at
17 http://oss.oracle.com/licenses/universal-foss-exception.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License, version 2.0, for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
27
28 #include "my_thread.h"
29
30 #ifdef _WIN32
31 #include "my_sys.h" /* my_osmaperr */
32 #include <process.h>
33 #include <signal.h>
34
35 struct thread_start_parameter
36 {
37 my_start_routine func;
38 void *arg;
39 };
40
41
win_thread_start(void * p)42 static unsigned int __stdcall win_thread_start(void *p)
43 {
44 struct thread_start_parameter *par= (struct thread_start_parameter *)p;
45 my_start_routine func= par->func;
46 void *arg= par->arg;
47 free(p);
48 (*func)(arg);
49 return 0;
50 }
51 #endif
52
53
54 /*
55 One time initialization. For simplicity, we assume initializer thread
56 does not exit within init_routine().
57 */
my_thread_once(my_thread_once_t * once_control,void (* init_routine)(void))58 int my_thread_once(my_thread_once_t *once_control, void (*init_routine)(void))
59 {
60 #ifndef _WIN32
61 return pthread_once(once_control, init_routine);
62 #else
63 LONG state;
64
65 /*
66 Do "dirty" read to find out if initialization is already done, to
67 save an interlocked operation in common case. Memory barriers are ensured by
68 Visual C++ volatile implementation.
69 */
70 if (*once_control == MY_THREAD_ONCE_DONE)
71 return 0;
72
73 state= InterlockedCompareExchange(once_control, MY_THREAD_ONCE_INPROGRESS,
74 MY_THREAD_ONCE_INIT);
75
76 switch(state)
77 {
78 case MY_THREAD_ONCE_INIT:
79 /* This is initializer thread */
80 (*init_routine)();
81 *once_control= MY_THREAD_ONCE_DONE;
82 break;
83
84 case MY_THREAD_ONCE_INPROGRESS:
85 /* init_routine in progress. Wait for its completion */
86 while(*once_control == MY_THREAD_ONCE_INPROGRESS)
87 {
88 Sleep(1);
89 }
90 break;
91 case MY_THREAD_ONCE_DONE:
92 /* Nothing to do */
93 break;
94 }
95 return 0;
96 #endif /* _WIN32 */
97 }
98
99
my_thread_create(my_thread_handle * thread,const my_thread_attr_t * attr,my_start_routine func,void * arg)100 int my_thread_create(my_thread_handle *thread, const my_thread_attr_t *attr,
101 my_start_routine func, void *arg)
102 {
103 #ifndef _WIN32
104 return pthread_create(&thread->thread, attr, func, arg);
105 #else
106 struct thread_start_parameter *par;
107 unsigned int stack_size;
108
109 par= (struct thread_start_parameter *)malloc(sizeof(*par));
110 if (!par)
111 goto error_return;
112
113 par->func= func;
114 par->arg= arg;
115 stack_size= attr ? attr->dwStackSize : 0;
116
117 thread->handle= (HANDLE)_beginthreadex(NULL, stack_size, win_thread_start,
118 par, 0, &thread->thread);
119
120 if (thread->handle)
121 {
122 /* Note that JOINABLE is default, so attr == NULL => JOINABLE. */
123 if (attr && attr->detachstate == MY_THREAD_CREATE_DETACHED)
124 {
125 /*
126 Close handles for detached threads right away to avoid leaking
127 handles. For joinable threads we need the handle during
128 my_thread_join. It will be closed there.
129 */
130 CloseHandle(thread->handle);
131 thread->handle= NULL;
132 }
133 return 0;
134 }
135
136 my_osmaperr(GetLastError());
137 free(par);
138
139 error_return:
140 thread->thread= 0;
141 thread->handle= NULL;
142 return 1;
143 #endif
144 }
145
146
my_thread_join(my_thread_handle * thread,void ** value_ptr)147 int my_thread_join(my_thread_handle *thread, void **value_ptr)
148 {
149 #ifndef _WIN32
150 return pthread_join(thread->thread, value_ptr);
151 #else
152 DWORD ret;
153 int result= 0;
154 ret= WaitForSingleObject(thread->handle, INFINITE);
155 if (ret != WAIT_OBJECT_0)
156 {
157 my_osmaperr(GetLastError());
158 result= 1;
159 }
160 if (thread->handle)
161 CloseHandle(thread->handle);
162 thread->thread= 0;
163 thread->handle= NULL;
164 return result;
165 #endif
166 }
167
168
my_thread_cancel(my_thread_handle * thread)169 int my_thread_cancel(my_thread_handle *thread)
170 {
171 #ifndef _WIN32
172 return pthread_cancel(thread->thread);
173 #else
174 BOOL ok= FALSE;
175
176 if (thread->handle)
177 {
178 ok= TerminateThread(thread->handle, 0);
179 CloseHandle(thread->handle);
180 }
181 if (ok)
182 return 0;
183
184 errno= EINVAL;
185 return -1;
186 #endif
187 }
188
189
my_thread_exit(void * value_ptr)190 void my_thread_exit(void *value_ptr)
191 {
192 #ifndef _WIN32
193 pthread_exit(value_ptr);
194 #else
195 _endthreadex(0);
196 #endif
197 }
198