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