1 /+
2 +            Copyright 2022 – 2024 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) nothrow @nogc{
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) nothrow @nogc{
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) nothrow @nogc{
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 	FnBind[] ret = [
90 		{q{const(char)*}, q{SDL_GetThreadName}, q{SDL_Thread* thread}},
91 		{q{SDL_threadID}, q{SDL_ThreadID}, q{}},
92 		{q{SDL_threadID}, q{SDL_GetThreadID}, q{SDL_Thread* thread}},
93 		{q{int}, q{SDL_SetThreadPriority}, q{SDL_ThreadPriority priority}},
94 		{q{void}, q{SDL_WaitThread}, q{SDL_Thread* thread, int* status}},
95 		{q{SDL_TLSID}, q{SDL_TLSCreate}, q{}},
96 		{q{void*}, q{SDL_TLSGet}, q{SDL_TLSID id}},
97 		{q{int}, q{SDL_TLSSet}, q{SDL_TLSID id, const(void)* value, TLSDestructor destructor}},
98 	];
99 	version(Win_OS2_GDK){
100 		{
101 			FnBind[] add = [
102 				{q{SDL_Thread*}, q{SDL_CreateThread}, q{SDL_ThreadFunction fn, const(char)* name, void* data, pfnSDL_CurrentBeginThread pfnBeginThread, pfnSDL_CurrentEndThread pFnEndThread}},
103 			];
104 			ret ~= add;
105 		}
106 		if(sdlSupport >= SDLSupport.v2_0_9){
107 			FnBind[] add = [
108 				{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}},
109 			];
110 			ret ~= add;
111 		}
112 	}else{
113 		{
114 			FnBind[] add = [
115 				{q{SDL_Thread*}, q{SDL_CreateThread}, q{SDL_ThreadFunction fn, const(char)* name, void* data}},
116 			];
117 			ret ~= add;
118 		}
119 		if(sdlSupport >= SDLSupport.v2_0_9){
120 			FnBind[] add = [
121 				{q{SDL_Thread*}, q{SDL_CreateThreadWithStackSize}, q{SDL_ThreadFunction fn, const(char)* name, const size_t stackSize, void* data}},
122 			];
123 			ret ~= add;
124 		}
125 	}
126 	if(sdlSupport >= SDLSupport.v2_0_2){
127 		FnBind[] add = [
128 			{q{void}, q{SDL_DetachThread}, q{SDL_Thread* thread}},
129 		];
130 		ret ~= add;
131 	}
132 	if(sdlSupport >= SDLSupport.v2_0_16){
133 		FnBind[] add = [
134 			{q{void}, q{SDL_TLSCleanup}, q{}},
135 		];
136 		ret ~= add;
137 	}
138 	return ret;
139 }()));