1 /+
2 +            Copyright 2022 – 2023 Aya Partridge
3 +          Copyright 2018 - 2022 Michael D. Parker
4 + Distributed under the Boost Software License, Version 1.0.
5 +     (See accompanying file LICENSE_1_0.txt or copy at
6 +           http://www.boost.org/LICENSE_1_0.txt)
7 +/
8 module sdl.thread;
9 
10 import bindbc.sdl.config;
11 import bindbc.sdl.codegen;
12 
13 struct SDL_Thread;
14 alias SDL_threadID = c_ulong;
15 alias SDL_TLSID = uint;
16 
17 alias SDL_ThreadPriority = int;
18 enum: SDL_ThreadPriority{
19 	SDL_THREAD_PRIORITY_LOW            = 0,
20 	SDL_THREAD_PRIORITY_NORMAL         = 1,
21 	SDL_THREAD_PRIORITY_HIGH           = 2,
22 }
23 static if(sdlSupport >= SDLSupport.v2_0_9)
24 enum: SDL_ThreadPriority{
25 	SDL_THREAD_PRIORITY_TIME_CRITICAL  = 3,
26 };
27 
28 extern(C) nothrow{
29 	alias SDL_ThreadFunction = int function(void* data);
30 	alias TLSDestructor = void function(void*);
31 }
32 
33 version(Windows)     version = Win_OS2_GDK;
34 else version(WinGDK) version = Win_OS2_GDK;
35 else version(OS2)    version = Win_OS2_GDK;
36 
37 version(Win_OS2_GDK){
38 	import core.stdc.stdint: uintptr_t;
39 	
40 	version(OS2){
41 		static if(sdlSupport >= SDLSupport.v2_0_6):
42 		
43 		private alias start_address = void function(void*);
44 		
45 		extern(C) @nogc nothrow{
46 			alias pfnSDL_CurrentBeginThread = uintptr_t function(start_address,void*,uint,void*);
47 			private int _beginthread(start_address,void*,uint,void*);
48 			alias SDL_beginthread = _beginthread;
49 			
50 			alias pfnSDL_CurrentEndThread = void function(uint);
51 			private void _endthread();
52 			alias SDL_endthread = _endthread;
53 		}
54 	}else{
55 		private alias start_address = extern(Windows) uint function(void*);
56 		
57 		extern(C) @nogc nothrow{
58 			/*
59 			On Windows, SDL_CreateThread/WithStackSize require the _beginthreadex/_endthreadex of
60 			the caller's process when using the DLL. As best as I can tell, this will be okay even
61 			when statically linking. If it does break, I'll need to add a new version identifier
62 			when BindBC_Static is specified in order to distingiuish between linking with the
63 			DLL's import library and statically linking with SDL.
64 			*/
65 			alias pfnSDL_CurrentBeginThread = uintptr_t function(void*,uint,start_address,void*,uint,uint*);
66 			private uintptr_t _beginthreadex(void*,uint,start_address,void*,uint,uint*);
67 			alias SDL_beginthread = _beginthreadex;
68 			
69 			alias pfnSDL_CurrentEndThread = void function(uint);
70 			private void _endthreadex(uint);
71 			alias SDL_endthread = _endthreadex;
72 		}
73 	}
74 	
75 	pragma(inline, true) @nogc nothrow{
76 		SDL_Thread* SDL_CreateThreadImpl(SDL_ThreadFunction fn, const(char)* name, void* data){
77 			return SDL_CreateThread(fn, name, data, &SDL_beginthread, &SDL_endthread);
78 		}
79 		
80 		static if(sdlSupport >= SDLSupport.v2_0_9){
81 			SDL_Thread* SDL_CreateThreadWithStackSizeImpl(SDL_ThreadFunction fn, const(char)* name, const(size_t) stackSize, void* data){
82 				return SDL_CreateThreadWithStackSize(fn, name, stackSize, data, &SDL_beginthread, &SDL_endthread);
83 			}
84 		}
85 	}
86 }
87 
88 mixin(joinFnBinds((){
89 	string[][] ret;
90 	version(Win_OS2_GDK){
91 		ret ~= makeFnBinds([
92 			[q{SDL_Thread*}, q{SDL_CreateThread}, q{SDL_ThreadFunction fn, const(char)* name, void* data, pfnSDL_CurrentBeginThread pfnBeginThread, pfnSDL_CurrentEndThread pfnEndThread}],
93 		]);
94 		static if(sdlSupport >= SDLSupport.v2_0_9){
95 			ret ~= makeFnBinds([
96 				[q{SDL_Thread*}, q{SDL_CreateThreadWithStackSize}, q{SDL_ThreadFunction fn, const(char)* name, const size_t stacksize, void* data, pfnSDL_CurrentBeginThread pfnBeginThread, pfnSDL_CurrentEndThread pfnEndThread}],
97 			]);
98 		}
99 	}else{
100 		ret ~= makeFnBinds([
101 			[q{SDL_Thread*}, q{SDL_CreateThread}, q{SDL_ThreadFunction fn, const(char)* name, void* data}],
102 		]);
103 		static if(sdlSupport >= SDLSupport.v2_0_9){
104 			ret ~= makeFnBinds([
105 				[q{SDL_Thread*}, q{SDL_CreateThreadWithStackSize}, q{SDL_ThreadFunction fn, const(char)* name, const size_t stacksize, void* data}],
106 			]);
107 		}
108 	}
109 	ret ~= makeFnBinds([
110 		[q{const(char)*}, q{SDL_GetThreadName}, q{SDL_Thread* thread}],
111 		[q{SDL_threadID}, q{SDL_ThreadID}, q{}],
112 		[q{SDL_threadID}, q{SDL_GetThreadID}, q{SDL_Thread* thread}],
113 		[q{int}, q{SDL_SetThreadPriority}, q{SDL_ThreadPriority priority}],
114 		[q{void}, q{SDL_WaitThread}, q{SDL_Thread* thread, int* status}],
115 		[q{SDL_TLSID}, q{SDL_TLSCreate}, q{}],
116 		[q{void*}, q{SDL_TLSGet}, q{SDL_TLSID id}],
117 		[q{int}, q{SDL_TLSSet}, q{SDL_TLSID id, const(void)* value, TLSDestructor destructor}],
118 	]);
119 	static if(sdlSupport >= SDLSupport.v2_0_2){
120 		ret ~= makeFnBinds([
121 			[q{void}, q{SDL_DetachThread}, q{SDL_Thread* thread}],
122 		]);
123 	}
124 	static if(sdlSupport >= SDLSupport.v2_0_16){
125 		ret ~= makeFnBinds([
126 			[q{void}, q{SDL_TLSCleanup}, q{}],
127 		]);
128 	}
129 	return ret;
130 }()));