]> git.proxmox.com Git - mirror_edk2.git/blame - EmulatorPkg/Unix/Host/Pthreads.c
EmulatorPkg: Remove all trailing whitespace
[mirror_edk2.git] / EmulatorPkg / Unix / Host / Pthreads.c
CommitLineData
949f388f 1/*++ @file
2 POSIX Pthreads to emulate APs and implement threads
3
4Copyright (c) 2011, Apple Inc. All rights reserved.
10d1be3e 5Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
6
949f388f 7This program and the accompanying materials
8are licensed and made available under the terms and conditions of the BSD License
9which accompanies this distribution. The full text of the license may be found at
10http://opensource.org/licenses/bsd-license.php
11
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15
16**/
17
18#include "SecMain.h"
19#include <pthread.h>
20
21
22UINTN
23EFIAPI
24PthreadMutexLock (
25 IN VOID *Mutex
26 )
27{
28 return (UINTN)pthread_mutex_lock ((pthread_mutex_t *)Mutex);
29}
30
31
32
33UINTN
34EFIAPI
35PthreadMutexUnLock (
36 IN VOID *Mutex
d18d8a1d 37 )
949f388f 38{
39 return (UINTN)pthread_mutex_unlock ((pthread_mutex_t *)Mutex);
40}
41
d18d8a1d 42
949f388f 43UINTN
44EFIAPI
45PthreadMutexTryLock (
46 IN VOID *Mutex
d18d8a1d 47 )
949f388f 48{
49 return (UINTN)pthread_mutex_trylock ((pthread_mutex_t *)Mutex);
50}
51
52
53VOID *
54PthreadMutexInit (
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
71UINTN
72PthreadMutexDestroy (
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
84typedef struct {
85 pthread_mutex_t Mutex;
10d1be3e 86 THREAD_THUNK_THREAD_ENTRY Start;
949f388f 87} THREAD_MANGLE;
88
89THREAD_MANGLE mThreadMangle = {
90 PTHREAD_MUTEX_INITIALIZER,
91 NULL
92};
93
94VOID *
95SecFakePthreadStart (
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 121UINTN
122PthreadCreate (
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
161VOID
162PthreadExit (
163 IN VOID *ValuePtr
164 )
d18d8a1d 165{
949f388f 166 pthread_exit (ValuePtr);
167 return;
168}
169
d18d8a1d 170
949f388f 171UINTN
172PthreadSelf (
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 183EMU_THREAD_THUNK_PROTOCOL gPthreadThunk = {
949f388f 184 GasketPthreadMutexLock,
185 GasketPthreadMutexUnLock,
186 GasketPthreadMutexTryLock,
187 GasketPthreadMutexInit,
188 GasketPthreadMutexDestroy,
189 GasketPthreadCreate,
190 GasketPthreadExit,
191 GasketPthreadSelf
192};
193
194
195EFI_STATUS
196PthreadOpen (
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
216EFI_STATUS
217PthreadClose (
218 IN EMU_IO_THUNK_PROTOCOL *This
219 )
220{
221 return EFI_SUCCESS;
222}
223
224
225EMU_IO_THUNK_PROTOCOL gPthreadThunkIo = {
10d1be3e 226 &gEmuThreadThunkProtocolGuid,
949f388f 227 NULL,
228 NULL,
229 0,
230 GasketPthreadOpen,
231 GasketPthreadClose,
232 NULL
233};
234
235