1 /* -*- Mode: C; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the Mozilla Public License Version 2.0.
7 // See license.mkd for licensing and copyright information.
8 // -------------------------------------------------------------------------*/
11 * Multithreaded support.
16 #ifndef SQUIRRELJME_MULTITHREAD_H
17 #define SQUIRRELJME_MULTITHREAD_H
19 #include "sjme/config.h"
20 #include "sjme/error.h"
22 #if defined(SJME_CONFIG_HAS_THREADS_FALLBACK)
24 #if defined(SJME_CONFIG_HAS_THREADS_PTHREAD)
25 #undef SJME_CONFIG_HAS_THREADS_PTHREAD
28 /* Clear Win32 threads. */
29 #if defined(SJME_CONFIG_HAS_THREADS_WIN32)
30 #undef SJME_CONFIG_HAS_THREADS_WIN32
34 #if defined(SJME_CONFIG_HAS_THREADS_WIN32)
35 #define WIN32_LEAN_AND_MEAN 1
39 #undef WIN32_LEAN_AND_MEAN
42 #if defined(SJME_CONFIG_HAS_THREADS_PTHREAD)
46 #if !defined(SJME_CONFIG_HAS_THREADS_ATOMIC)
47 #define SJME_CONFIG_HAS_THREADS_ATOMIC
51 #include "sjme/stdTypes.h"
52 #include "sjme/atomic.h"
56 #ifndef SJME_CXX_IS_EXTERNED
57 #define SJME_CXX_IS_EXTERNED
58 #define SJME_CXX_SQUIRRELJME_MULTITHREAD_H
60 #endif /* #ifdef SJME_CXX_IS_EXTERNED */
61 #endif /* #ifdef __cplusplus */
63 /*--------------------------------------------------------------------------*/
65 /* clang-format off */
67 #if defined(SJME_CONFIG_HAS_THREADS_PTHREAD)
68 /** A single thread. */
69 typedef pthread_t sjme_thread
;
71 /* On these systems pthread_t is a pointer. */
72 #if defined(SJME_CONFIG_HAS_MACOS) || \
73 defined(SJME_CONFIG_HAS_EMSCRIPTEN)
74 /** The thread type. */
75 #define SJME_TYPEOF_BASIC_sjme_thread SJME_TYPEOF_BASIC_sjme_pointer
77 /** Is a thread a pointer? */
78 #define SJME_TYPEOF_IS_POINTER_sjme_thread 1
80 /** The thread type. */
81 #define SJME_TYPEOF_BASIC_sjme_thread SJME_TYPEOF_BASIC_sjme_intPointer
83 /** Is a thread a pointer? */
84 #define SJME_TYPEOF_IS_POINTER_sjme_thread 0
88 typedef sjme_pointer sjme_thread_result
;
90 /** Thread parameter. */
91 typedef sjme_pointer sjme_thread_parameter
;
93 /** Null thread handle. */
94 #define SJME_THREAD_NULL ((unsigned long)0)
96 /** Error as thread result. */
97 #define SJME_THREAD_RESULT(err) ((sjme_pointer)(err))
99 /** Thread result cast to error. */
100 #define SJME_THREAD_RESULT_AS_ERROR(result) \
101 ((sjme_errorCode)((sjme_intPointer)(result)))
103 /** Calling convention to use for thread entry points. */
104 #define sjme_attrThreadCall
105 #elif defined(SJME_CONFIG_HAS_THREADS_WIN32)
106 /** A single thread. */
107 typedef HANDLE sjme_thread
;
109 /** The thread type. */
110 #define SJME_TYPEOF_BASIC_sjme_thread SJME_TYPEOF_BASIC_sjme_pointer
112 /** Is a thread a pointer? */
113 #define SJME_TYPEOF_IS_POINTER_sjme_thread 1
115 /** Thread result. */
116 typedef DWORD sjme_thread_result
;
118 /** Thread parameter. */
119 typedef LPVOID sjme_thread_parameter
;
121 /** Null thread handle. */
122 #define SJME_THREAD_NULL NULL
124 /** Error as thread result. */
125 #define SJME_THREAD_RESULT(err) ((DWORD)(err))
127 /** Thread result cast to error. */
128 #define SJME_THREAD_RESULT_AS_ERROR(result) ((sjme_errorCode)(result))
130 /** Calling convention to use for thread entry points. */
131 #define sjme_attrThreadCall WINAPI
133 /** Threads not supported. */
134 typedef struct sjme_thread_unsupported
137 } sjme_thread_unsupported
;
139 /** A single thread. */
140 typedef sjme_thread_unsupported
* sjme_thread
;
142 /** The thread type. */
143 #define SJME_TYPEOF_BASIC_sjme_thread SJME_TYPEOF_BASIC_sjme_pointer
145 /** Is a thread a pointer? */
146 #define SJME_TYPEOF_IS_POINTER_sjme_thread 1
148 /** Thread result. */
149 typedef int sjme_thread_result
;
151 /** Thread parameter. */
152 typedef sjme_pointer sjme_thread_parameter
;
154 /** Null thread handle. */
155 #define SJME_THREAD_NULL NULL
157 /** Error as thread result. */
158 #define SJME_THREAD_RESULT(err) ((int)(err))
160 /** Thread result cast to error. */
161 #define SJME_THREAD_RESULT_AS_ERROR(result) ((sjme_errorCode)(result))
163 /** Calling convention to use for thread entry points. */
164 #define sjme_attrThreadCall
167 /* clang-format on */
170 SJME_ATOMIC_DECLARE(sjme_thread
, 0);
173 * Main thread function type.
175 * @param anything Passed from @c sjme_thread_new .
176 * @return Thread resultant value.
179 typedef sjme_thread_result (sjme_attrThreadCall
*sjme_thread_mainFunc
)(
180 sjme_attrInNullable sjme_thread_parameter anything
);
187 typedef struct sjme_thread_spinLock
189 /** The thread that is currently poking this lock. */
190 sjme_atomic_sjme_thread poke
;
192 /** The thread that owns this lock. */
193 sjme_atomic_sjme_thread owner
;
196 sjme_atomic_sjme_jint count
;
197 } sjme_thread_spinLock
;
200 * Returns the current thread.
202 * @param outThread The resultant thread.
203 * @return On any errors if applicable.
206 sjme_errorCode
sjme_thread_current(
207 sjme_attrInOutNotNull sjme_thread
* outThread
);
210 * Compares equality between two threads.
212 * @param aThread The first thread.
213 * @param bThread The second thread.
214 * @return The resultant equality.
217 sjme_jboolean
sjme_thread_equal(
218 sjme_attrInNullable sjme_thread aThread
,
219 sjme_attrInNullable sjme_thread bThread
);
222 * Creates a new thread and immediately starts running it.
224 * @param outThread The resultant thread.
225 * @param outThreadId The resultant thread ID, is optional.
226 * @param inMain The main function for the thread.
227 * @param anything Any value to pass to it.
228 * @return Any error code if applicable.
231 sjme_errorCode
sjme_thread_new(
232 sjme_attrInOutNotNull sjme_thread
* outThread
,
233 sjme_attrInNullable sjme_intPointer
* outThreadId
,
234 sjme_attrInNotNull sjme_thread_mainFunc inMain
,
235 sjme_attrInNullable sjme_pointer anything
);
240 * @param inLock The lock to grab.
241 * @return Any resultant error, if any.
244 sjme_errorCode
sjme_thread_spinLockGrab(sjme_thread_spinLock
* inLock
);
247 * Releases a spin lock.
249 * @param inLock The lock to release.
250 * @param outCount Optional count after lock.
251 * @return Any resultant error, if any.
254 sjme_errorCode
sjme_thread_spinLockRelease(
255 sjme_attrInNotNull sjme_thread_spinLock
* inLock
,
256 sjme_attrOutNullable sjme_jint
* outCount
);
263 void sjme_thread_yield(void);
265 /*--------------------------------------------------------------------------*/
269 #ifdef SJME_CXX_SQUIRRELJME_MULTITHREAD_H
271 #undef SJME_CXX_SQUIRRELJME_MULTITHREAD_H
272 #undef SJME_CXX_IS_EXTERNED
273 #endif /* #ifdef SJME_CXX_SQUIRRELJME_MULTITHREAD_H */
274 #endif /* #ifdef __cplusplus */
276 #endif /* SQUIRRELJME_MULTITHREAD_H */