TianoCore EDK2 master
Loading...
Searching...
No Matches
Pthreads.c
1/*++ @file
2 POSIX Pthreads to emulate APs and implement threads
3
4Copyright (c) 2011, Apple Inc. All rights reserved.
5Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.<BR>
6
7SPDX-License-Identifier: BSD-2-Clause-Patent
8
9
10**/
11
12#include "Host.h"
13#include <pthread.h>
14
16EFIAPI
17PthreadMutexLock (
18 IN VOID *Mutex
19 )
20{
21 return (UINTN)pthread_mutex_lock ((pthread_mutex_t *)Mutex);
22}
23
25EFIAPI
26PthreadMutexUnLock (
27 IN VOID *Mutex
28 )
29{
30 return (UINTN)pthread_mutex_unlock ((pthread_mutex_t *)Mutex);
31}
32
34EFIAPI
35PthreadMutexTryLock (
36 IN VOID *Mutex
37 )
38{
39 return (UINTN)pthread_mutex_trylock ((pthread_mutex_t *)Mutex);
40}
41
42VOID *
43PthreadMutexInit (
44 IN VOID
45 )
46{
47 pthread_mutex_t *Mutex;
48 int err;
49
50 Mutex = malloc (sizeof (pthread_mutex_t));
51 err = pthread_mutex_init (Mutex, NULL);
52 if (err == 0) {
53 return Mutex;
54 }
55
56 return NULL;
57}
58
60PthreadMutexDestroy (
61 IN VOID *Mutex
62 )
63{
64 if (Mutex != NULL) {
65 return pthread_mutex_destroy ((pthread_mutex_t *)Mutex);
66 }
67
68 return -1;
69}
70
71// Can't store this data on PthreadCreate stack so we need a global
72typedef struct {
73 pthread_mutex_t Mutex;
74 THREAD_THUNK_THREAD_ENTRY Start;
76
77THREAD_MANGLE mThreadMangle = {
78 PTHREAD_MUTEX_INITIALIZER,
79 NULL
80};
81
82VOID *
83SecFakePthreadStart (
84 VOID *Context
85 )
86{
87 THREAD_THUNK_THREAD_ENTRY Start;
88 sigset_t SigMask;
89
90 // Save global on the stack before we unlock
91 Start = mThreadMangle.Start;
92 pthread_mutex_unlock (&mThreadMangle.Mutex);
93
94 // Mask all signals to the APs
95 sigfillset (&SigMask);
96 pthread_sigmask (SIG_BLOCK, &SigMask, NULL);
97
98 //
99 // We have to start the thread in SEC as we need to follow
100 // OS X calling conventions. We can then call back into
101 // to the callers Start.
102 //
103 // This is a great example of how all problems in computer
104 // science can be solved by adding another level of indirection
105 //
106 return (VOID *)ReverseGasketUint64 ((UINTN)Start, (UINTN)Context);
107}
108
109UINTN
110PthreadCreate (
111 IN VOID *Thread,
112 IN VOID *Attribute,
113 IN THREAD_THUNK_THREAD_ENTRY Start,
114 IN VOID *Context
115 )
116{
117 int err;
118 BOOLEAN EnabledOnEntry;
119
120 //
121 // Threads inherit interrupt state so disable interrupts before we start thread
122 //
123 if (SecInterruptEanbled ()) {
124 SecDisableInterrupt ();
125 EnabledOnEntry = TRUE;
126 } else {
127 EnabledOnEntry = FALSE;
128 }
129
130 // Acquire lock for global, SecFakePthreadStart runs in a different thread.
131 pthread_mutex_lock (&mThreadMangle.Mutex);
132 mThreadMangle.Start = Start;
133
134 err = pthread_create (Thread, Attribute, SecFakePthreadStart, Context);
135 if (err != 0) {
136 // Thread failed to launch so release the lock;
137 pthread_mutex_unlock (&mThreadMangle.Mutex);
138 }
139
140 if (EnabledOnEntry) {
141 // Restore interrupt state
142 SecEnableInterrupt ();
143 }
144
145 return err;
146}
147
148VOID
149PthreadExit (
150 IN VOID *ValuePtr
151 )
152{
153 pthread_exit (ValuePtr);
154 return;
155}
156
157UINTN
158PthreadSelf (
159 VOID
160 )
161{
162 // POSIX currently allows pthread_t to be a structure or arithmetic type.
163 // Check out sys/types.h to make sure this will work if you are porting.
164 // On OS X (Darwin) pthread_t is a pointer to a structure so this code works.
165 return (UINTN)pthread_self ();
166}
167
168EMU_THREAD_THUNK_PROTOCOL gPthreadThunk = {
169 GasketPthreadMutexLock,
170 GasketPthreadMutexUnLock,
171 GasketPthreadMutexTryLock,
172 GasketPthreadMutexInit,
173 GasketPthreadMutexDestroy,
174 GasketPthreadCreate,
175 GasketPthreadExit,
176 GasketPthreadSelf
177};
178
180PthreadOpen (
182 )
183{
184 if (This->Instance != 0) {
185 // Only single instance is supported
186 return EFI_NOT_FOUND;
187 }
188
189 if (This->ConfigString[0] == L'0') {
190 // If AP count is zero no need for threads
191 return EFI_NOT_FOUND;
192 }
193
194 This->Interface = &gPthreadThunk;
195
196 return EFI_SUCCESS;
197}
198
200PthreadClose (
202 )
203{
204 return EFI_SUCCESS;
205}
206
207EMU_IO_THUNK_PROTOCOL gPthreadThunkIo = {
208 &gEmuThreadThunkProtocolGuid,
209 NULL,
210 NULL,
211 0,
212 GasketPthreadOpen,
213 GasketPthreadClose,
214 NULL
215};
UINT64 UINTN
#define NULL
Definition: Base.h:319
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112