Pthreads.c 4.3 KB

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