]> git.proxmox.com Git - mirror_edk2.git/blob - EmulatorPkg/Unix/Host/Pthreads.c
EmulatorPkg: Remove all trailing whitespace
[mirror_edk2.git] / EmulatorPkg / Unix / Host / Pthreads.c
1 /*++ @file
2 POSIX Pthreads to emulate APs and implement threads
3
4 Copyright (c) 2011, Apple Inc. All rights reserved.
5 Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
6
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
18 #include "SecMain.h"
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
37 )
38 {
39 return (UINTN)pthread_mutex_unlock ((pthread_mutex_t *)Mutex);
40 }
41
42
43 UINTN
44 EFIAPI
45 PthreadMutexTryLock (
46 IN VOID *Mutex
47 )
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;
60
61 Mutex = malloc (sizeof (pthread_mutex_t));
62 err = pthread_mutex_init (Mutex, NULL);
63 if (err == 0) {
64 return Mutex;
65 }
66
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 }
79
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;
86 THREAD_THUNK_THREAD_ENTRY Start;
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 {
99 THREAD_THUNK_THREAD_ENTRY Start;
100 sigset_t SigMask;
101
102 // Save global on the stack before we unlock
103 Start = mThreadMangle.Start;
104 pthread_mutex_unlock (&mThreadMangle.Mutex);
105
106 // Mask all signals to the APs
107 sigfillset (&SigMask);
108 pthread_sigmask (SIG_BLOCK, &SigMask, NULL);
109
110 //
111 // We have to start the thread in SEC as we need to follow
112 // OS X calling conventions. We can then call back into
113 // to the callers Start.
114 //
115 // This is a great example of how all problems in computer
116 // science can be solved by adding another level of indirection
117 //
118 return (VOID *)ReverseGasketUint64 ((CALL_BACK)Start, (UINTN)Context);
119 }
120
121 UINTN
122 PthreadCreate (
123 IN VOID *Thread,
124 IN VOID *Attribute,
125 IN THREAD_THUNK_THREAD_ENTRY Start,
126 IN VOID *Context
127 )
128 {
129 int err;
130 BOOLEAN EnabledOnEntry;
131
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 }
141
142 // Aquire lock for global, SecFakePthreadStart runs in a different thread.
143 pthread_mutex_lock (&mThreadMangle.Mutex);
144 mThreadMangle.Start = Start;
145
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 }
151
152 if (EnabledOnEntry) {
153 // Restore interrupt state
154 SecEnableInterrupt ();
155 }
156
157 return err;
158 }
159
160
161 VOID
162 PthreadExit (
163 IN VOID *ValuePtr
164 )
165 {
166 pthread_exit (ValuePtr);
167 return;
168 }
169
170
171 UINTN
172 PthreadSelf (
173 VOID
174 )
175 {
176 // POSIX currently allows pthread_t to be a structure or arithmetic type.
177 // Check out sys/types.h to make sure this will work if you are porting.
178 // On OS X (Darwin) pthread_t is a pointer to a structure so this code works.
179 return (UINTN)pthread_self ();
180 }
181
182
183 EMU_THREAD_THUNK_PROTOCOL gPthreadThunk = {
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 }
204
205 if (This->ConfigString[0] == L'0') {
206 // If AP count is zero no need for threads
207 return EFI_NOT_FOUND;
208 }
209
210 This->Interface = &gPthreadThunk;
211
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 = {
226 &gEmuThreadThunkProtocolGuid,
227 NULL,
228 NULL,
229 0,
230 GasketPthreadOpen,
231 GasketPthreadClose,
232 NULL
233 };
234
235