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