]> git.proxmox.com Git - mirror_edk2.git/blame - EmulatorPkg/Unix/Host/Pthreads.c
EmbeddedPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / EmulatorPkg / Unix / Host / Pthreads.c
CommitLineData
79e4f2a5
RN
1/*++ @file\r
2 POSIX Pthreads to emulate APs and implement threads\r
3\r
4Copyright (c) 2011, Apple Inc. All rights reserved.\r
5Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
6\r
7This program and the accompanying materials\r
8are licensed and made available under the terms and conditions of the BSD License\r
9which accompanies this distribution. The full text of the license may be found at\r
10http://opensource.org/licenses/bsd-license.php\r
11\r
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15\r
16**/\r
17\r
18#include "Host.h"\r
19#include <pthread.h>\r
20\r
21\r
22UINTN\r
23EFIAPI\r
24PthreadMutexLock (\r
25 IN VOID *Mutex\r
26 )\r
27{\r
28 return (UINTN)pthread_mutex_lock ((pthread_mutex_t *)Mutex);\r
29}\r
30\r
31\r
32\r
33UINTN\r
34EFIAPI\r
35PthreadMutexUnLock (\r
36 IN VOID *Mutex\r
37 )\r
38{\r
39 return (UINTN)pthread_mutex_unlock ((pthread_mutex_t *)Mutex);\r
40}\r
41\r
42\r
43UINTN\r
44EFIAPI\r
45PthreadMutexTryLock (\r
46 IN VOID *Mutex\r
47 )\r
48{\r
49 return (UINTN)pthread_mutex_trylock ((pthread_mutex_t *)Mutex);\r
50}\r
51\r
52\r
53VOID *\r
54PthreadMutexInit (\r
55 IN VOID\r
56 )\r
57{\r
58 pthread_mutex_t *Mutex;\r
59 int err;\r
60\r
61 Mutex = malloc (sizeof (pthread_mutex_t));\r
62 err = pthread_mutex_init (Mutex, NULL);\r
63 if (err == 0) {\r
64 return Mutex;\r
65 }\r
66\r
67 return NULL;\r
68}\r
69\r
70\r
71UINTN\r
72PthreadMutexDestroy (\r
73 IN VOID *Mutex\r
74 )\r
75{\r
76 if (Mutex != NULL) {\r
77 return pthread_mutex_destroy ((pthread_mutex_t *)Mutex);\r
78 }\r
79\r
80 return -1;\r
81}\r
82\r
83// Can't store this data on PthreadCreate stack so we need a global\r
84typedef struct {\r
85 pthread_mutex_t Mutex;\r
86 THREAD_THUNK_THREAD_ENTRY Start;\r
87} THREAD_MANGLE;\r
88\r
89THREAD_MANGLE mThreadMangle = {\r
90 PTHREAD_MUTEX_INITIALIZER,\r
91 NULL\r
92};\r
93\r
94VOID *\r
95SecFakePthreadStart (\r
96 VOID *Context\r
97 )\r
98{\r
99 THREAD_THUNK_THREAD_ENTRY Start;\r
100 sigset_t SigMask;\r
101\r
102 // Save global on the stack before we unlock\r
103 Start = mThreadMangle.Start;\r
104 pthread_mutex_unlock (&mThreadMangle.Mutex);\r
105\r
106 // Mask all signals to the APs\r
107 sigfillset (&SigMask);\r
108 pthread_sigmask (SIG_BLOCK, &SigMask, NULL);\r
109\r
110 //\r
111 // We have to start the thread in SEC as we need to follow\r
112 // OS X calling conventions. We can then call back into\r
113 // to the callers Start.\r
114 //\r
115 // This is a great example of how all problems in computer\r
116 // science can be solved by adding another level of indirection\r
117 //\r
118 return (VOID *)ReverseGasketUint64 ((CALL_BACK)Start, (UINTN)Context);\r
119}\r
120\r
121UINTN\r
122PthreadCreate (\r
123 IN VOID *Thread,\r
124 IN VOID *Attribute,\r
125 IN THREAD_THUNK_THREAD_ENTRY Start,\r
126 IN VOID *Context\r
127 )\r
128{\r
129 int err;\r
130 BOOLEAN EnabledOnEntry;\r
131\r
132 //\r
133 // Threads inherit interrupt state so disable interrupts before we start thread\r
134 //\r
135 if (SecInterruptEanbled ()) {\r
136 SecDisableInterrupt ();\r
137 EnabledOnEntry = TRUE;\r
138 } else {\r
139 EnabledOnEntry = FALSE;\r
140 }\r
141\r
142 // Aquire lock for global, SecFakePthreadStart runs in a different thread.\r
143 pthread_mutex_lock (&mThreadMangle.Mutex);\r
144 mThreadMangle.Start = Start;\r
145\r
146 err = pthread_create (Thread, Attribute, SecFakePthreadStart, Context);\r
147 if (err != 0) {\r
148 // Thread failed to launch so release the lock;\r
149 pthread_mutex_unlock (&mThreadMangle.Mutex);\r
150 }\r
151\r
152 if (EnabledOnEntry) {\r
153 // Restore interrupt state\r
154 SecEnableInterrupt ();\r
155 }\r
156\r
157 return err;\r
158}\r
159\r
160\r
161VOID\r
162PthreadExit (\r
163 IN VOID *ValuePtr\r
164 )\r
165{\r
166 pthread_exit (ValuePtr);\r
167 return;\r
168}\r
169\r
170\r
171UINTN\r
172PthreadSelf (\r
173 VOID\r
174 )\r
175{\r
176 // POSIX currently allows pthread_t to be a structure or arithmetic type.\r
177 // Check out sys/types.h to make sure this will work if you are porting.\r
178 // On OS X (Darwin) pthread_t is a pointer to a structure so this code works.\r
179 return (UINTN)pthread_self ();\r
180}\r
181\r
182\r
183EMU_THREAD_THUNK_PROTOCOL gPthreadThunk = {\r
184 GasketPthreadMutexLock,\r
185 GasketPthreadMutexUnLock,\r
186 GasketPthreadMutexTryLock,\r
187 GasketPthreadMutexInit,\r
188 GasketPthreadMutexDestroy,\r
189 GasketPthreadCreate,\r
190 GasketPthreadExit,\r
191 GasketPthreadSelf\r
192};\r
193\r
194\r
195EFI_STATUS\r
196PthreadOpen (\r
197 IN EMU_IO_THUNK_PROTOCOL *This\r
198 )\r
199{\r
200 if (This->Instance != 0) {\r
201 // Only single instance is supported\r
202 return EFI_NOT_FOUND;\r
203 }\r
204\r
205 if (This->ConfigString[0] == L'0') {\r
206 // If AP count is zero no need for threads\r
207 return EFI_NOT_FOUND;\r
208 }\r
209\r
210 This->Interface = &gPthreadThunk;\r
211\r
212 return EFI_SUCCESS;\r
213}\r
214\r
215\r
216EFI_STATUS\r
217PthreadClose (\r
218 IN EMU_IO_THUNK_PROTOCOL *This\r
219 )\r
220{\r
221 return EFI_SUCCESS;\r
222}\r
223\r
224\r
225EMU_IO_THUNK_PROTOCOL gPthreadThunkIo = {\r
226 &gEmuThreadThunkProtocolGuid,\r
227 NULL,\r
228 NULL,\r
229 0,\r
230 GasketPthreadOpen,\r
231 GasketPthreadClose,\r
232 NULL\r
233};\r
234\r
235\r