graphics updates
[voxelands-alt.git] / src / lib / thread.c
blob35aed024b8661e97bea9d04cf58761a2b28ea4f5
1 /************************************************************************
2 * auth.c
3 * voxelands - 3d voxel world sandbox game
4 * Copyright (C) Lisa 'darkrose' Milne 2016 <lisa@ltmnet.com>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>
18 ************************************************************************/
20 #include "thread.h"
21 #include "list.h"
22 #include "array.h"
24 #include <stdlib.h>
25 #ifndef WIN32
26 #include <signal.h>
27 #endif
29 #define IO_THREAD_STOPPED 0
30 #define IO_THREAD_RUNNING 1
31 static thread_t *threads = NULL;
32 static mutex_t *mutexes = NULL;
34 /* create a new thread */
35 thread_t *thread_create(void *(*func)(), array_t *args)
37 thread_t *t = malloc(sizeof(thread_t));
39 t->state = IO_THREAD_RUNNING;
40 t->func = func;
41 t->args = args;
42 t->exit = 0;
44 threads = list_push((void**)&threads,t);
46 #ifndef WIN32
47 pthread_attr_init(&t->attr);
48 pthread_attr_setdetachstate(&t->attr, PTHREAD_CREATE_JOINABLE);
49 pthread_create(&t->thread, &t->attr, t->func, (void *)t);
50 #else
51 t->thread = CreateThread(NULL, 0, t->func, (void*)t, 0, NULL);
52 #endif
54 return t;
57 /* destroy a thread */
58 void thread_free(thread_t *t)
60 if (!t)
61 return;
63 thread_stop(t);
64 #ifndef WIN32
65 pthread_attr_destroy(&t->attr);
66 #endif
67 if (t->args)
68 array_free(t->args,1);
69 free(t);
72 /* exit from a thread */
73 void thread_exit(thread_t *t, int state)
75 if (!t)
76 return;
78 t->exit = state;
79 t->state = IO_THREAD_STOPPED;
80 #ifndef WIN32
81 pthread_exit(NULL);
82 #else
83 ExitThread(state);
84 #endif
87 /* stop a thread */
88 void thread_stop(thread_t *t)
90 if (!t)
91 return;
93 if (t->state == IO_THREAD_RUNNING) {
94 t->state = IO_THREAD_STOPPED;
95 #ifndef WIN32
96 pthread_kill(t->thread,SIGKILL);
97 #else
98 TerminateThread(t->thread,0);
99 CloseHandle(t->thread);
100 #endif
104 /* restart a thread */
105 int thread_wake(thread_t *t)
107 if (!t)
108 return 0;
110 if (t->state == IO_THREAD_RUNNING) {
111 #ifndef WIN32
112 pthread_kill(t->thread,SIGCONT);
113 #else
114 ResumeThread(t->thread);
115 #endif
116 }else{
117 t->state = IO_THREAD_RUNNING;
118 #ifndef WIN32
119 pthread_create(&t->thread, &t->attr, t->func, (void *)t);
120 #else
121 t->thread = CreateThread(NULL, 0, t->func, (void*)t, 0, NULL);
122 #endif
124 return 0;
127 /* wait for a thread to exit */
128 void thread_wait(thread_t *t)
130 if (!t)
131 return;
133 if (t->state == IO_THREAD_RUNNING) {
134 #ifndef WIN32
135 pthread_join(t->thread,NULL);
136 #else
137 WaitForSingleObject(t->thread, 2000);
138 CloseHandle(t->thread);
139 #endif
141 t->state = IO_THREAD_STOPPED;
144 threadid_t thread_get_current_id()
146 #ifdef WIN32
147 return GetCurrentThreadId();
148 #else
149 return pthread_self();
150 #endif
153 /* create a mutex */
154 mutex_t *mutex_create()
156 mutex_t *m = malloc(sizeof(mutex_t));
158 #ifndef WIN32
159 pthread_mutexattr_init(&m->attr);
160 pthread_mutexattr_settype(&m->attr, PTHREAD_MUTEX_RECURSIVE);
161 pthread_mutex_init(&m->mut, &m->attr);
162 #else
163 InitializeCriticalSection(&m->mut);
164 #endif
166 m->id = thread_get_current_id();
167 m->count = 0;
169 mutexes = list_push((void**)&mutexes,m);
171 return m;
174 /* destroy a mutex */
175 void mutex_free(mutex_t *m)
177 mutex_unlock(m);
178 #ifndef WIN32
179 pthread_mutex_destroy(&m->mut);
180 pthread_mutexattr_destroy(&m->attr);
181 #else
182 DeleteCriticalSection(&m->mut);
183 #endif
185 mutexes = list_remove((void**)&mutexes,m);
186 free(m);
189 /* lock a mutex */
190 void mutex_lock(mutex_t *m)
192 if (mutex_trylock(m)) {
193 if (m->id == thread_get_current_id())
194 m->count++;
198 /* try to lock a mutex - return non-zero if not locked */
199 int mutex_trylock(mutex_t *m)
201 #ifndef WIN32
202 if (pthread_mutex_trylock(&m->mut))
203 return 1;
204 #else
205 if (!TryEnterCriticalSection(&m->mut))
206 return 1;
207 #endif
208 m->id = thread_get_current_id();
209 m->count = 1;
211 return 0;
214 /* unlock a mutex */
215 void mutex_unlock(mutex_t *m)
217 m->count--;
218 if (m->count > 0)
219 return;
220 #ifndef WIN32
221 pthread_mutex_unlock(&m->mut);
222 #else
223 LeaveCriticalSection(&m->mut);
224 #endif
227 static void *mutex_test_lock_t(thread_t *t)
229 int r = mutex_trylock(((mutex_t**)(t->args->data))[0]);
230 thread_exit(t,r);
231 return NULL;
234 /* try to force a mutex to unlock */
235 void mutex_unlock_complete(mutex_t *m)
237 array_t *a;
238 thread_t *t;
240 a = array_create(ARRAY_TYPE_PTR);
241 array_push_ptr(a,m);
242 t = thread_create(mutex_test_lock_t,a);
243 thread_wait(t);
244 while (t->exit) {
245 thread_wake(t);
246 thread_wait(t);