The Pedigree Project  0.1
pthread-syscalls.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "PosixSubsystem.h"
21 #include "pedigree/kernel/errors.h"
22 #include "pedigree/kernel/process/PerProcessorScheduler.h"
23 #include "pedigree/kernel/process/Process.h"
24 #include "pedigree/kernel/process/Scheduler.h"
25 #include "pedigree/kernel/syscallError.h"
26 #include "pedigree/kernel/utilities/List.h"
27 #include "pedigree/kernel/utilities/Tree.h"
28 #include <pthread-syscalls.h>
29 
31 #define FUTEX_WAIT 0
32 #define FUTEX_WAKE 1
33 #define FUTEX_FD 2
34 #define FUTEX_REQUEUE 3
35 #define FUTEX_CMP_REQUEUE 4
36 #define FUTEX_WAKE_OP 5
37 #define FUTEX_LOCK_PI 6
38 #define FUTEX_UNLOCK_PI 7
39 #define FUTEX_TRYLOCK_PI 8
40 #define FUTEX_WAIT_BITSET 9
41 #define FUTEX_PRIVATE 128
42 #define FUTEX_CLOCK_REALTIME 256
43 
44 extern "C" {
45 extern void pthread_stub();
46 extern char pthread_stub_end;
47 }
48 
49 static Tree<int *, List<Thread *> *> g_futexes;
50 
51 int posix_futex(
52  int *uaddr, int futex_op, int val, const struct timespec *timeout)
53 {
54  Thread *pThread = Processor::information().getCurrentThread();
55  Process *pProcess = pThread->getParent();
56  PosixSubsystem *pSubsystem =
57  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
58  if (!pSubsystem)
59  {
60  ERROR("No subsystem for this process!");
61  return -1;
62  }
63 
64  PT_NOTICE(
65  "futex(" << Hex << uaddr << ", " << futex_op << ", " << val << ", "
66  << timeout << ")");
67 
68  if (!(futex_op & FUTEX_PRIVATE))
69  {
70  PT_NOTICE(" -> warning: public futexes are not yet supported");
71  }
72 
73  if (futex_op & FUTEX_CLOCK_REALTIME)
74  {
75  PT_NOTICE(" -> warning: clock choice (monotonic vs realtime) is not "
76  "yet supported");
77  futex_op &= ~FUTEX_CLOCK_REALTIME;
78  }
79 
80  futex_op &= ~FUTEX_PRIVATE;
81 
82  int r = 0;
83  int supported = 0;
84 
85  switch (futex_op)
86  {
87  case FUTEX_WAIT:
88  {
89  PT_NOTICE(" -> FUTEX_WAIT");
90 
92  if (*uaddr != val)
93  {
94  PT_NOTICE(" -> value changed");
95  SYSCALL_ERROR(NoMoreProcesses); // EAGAIN
96  r = -1;
97  }
98  else
99  {
100  bool newLock = false;
101 
102  List<Thread *> *threads = g_futexes.lookup(uaddr);
103  if (!threads)
104  {
105  threads = new List<Thread *>;
106  threads->pushBack(pThread);
107  g_futexes.insert(uaddr, threads);
108  }
109 
110  // good to go for sleeping
112  PT_NOTICE(" -> waiting...");
113  Processor::information().getScheduler().sleep();
114  PT_NOTICE(" -> waiting complete!");
115  }
116  break;
117  }
118 
119  case FUTEX_WAKE:
120  {
121  PT_NOTICE(" -> FUTEX_WAKE");
122 
123  List<Thread *> *threads = g_futexes.lookup(uaddr);
124  if (threads)
125  {
126  int woken = 0;
127  for (int i = 0; i < val && threads->count() > 0; ++i)
128  {
129  Thread *pWakeThread = threads->popFront();
130  PT_NOTICE(" -> waking " << pWakeThread);
131  pWakeThread->getLock().acquire();
132  pWakeThread->setStatus(Thread::Ready);
133  pWakeThread->getLock().release();
134  PT_NOTICE(" -> woken!");
135  ++woken;
136  }
137 
138  PT_NOTICE(" -> woke " << Dec << woken << " threads.");
139  r = woken;
140  }
141  break;
142  }
143 
144  default:
145  PT_NOTICE(" -> unsupported futex operation");
146  SYSCALL_ERROR(Unimplemented);
147  r = -1;
148  }
149 
150  PT_NOTICE(" -> " << Dec << r);
151  return r;
152 }
153 
157 void pedigree_copy_posix_thread(
158  Thread *origThread, PosixSubsystem *origSubsystem, Thread *newThread,
159  PosixSubsystem *newSubsystem)
160 {
161  PosixSubsystem::PosixThread *pOldPosixThread =
162  origSubsystem->getThread(origThread->getId());
163  if (!pOldPosixThread)
164  {
165  // Nothing to see here.
166  return;
167  }
168 
169  PosixSubsystem::PosixThread *pNewPosixThread =
171  pNewPosixThread->pThread = newThread;
172  pNewPosixThread->returnValue = 0;
173 
174  // Copy thread-specific data across.
176  pOldPosixThread->m_ThreadData.begin();
177  it != pOldPosixThread->m_ThreadData.end(); ++it)
178  {
179  size_t key = it.key();
180  PosixSubsystem::PosixThreadKey *data = it.value();
181 
182  pNewPosixThread->addThreadData(key, data);
183  pNewPosixThread->m_ThreadKeys.set(key);
184  }
185 
186  pNewPosixThread->lastDataKey = pOldPosixThread->lastDataKey;
187  pNewPosixThread->nextDataKey = pOldPosixThread->nextDataKey;
188 
189  newSubsystem->insertThread(newThread->getId(), pNewPosixThread);
190 }
191 
199 void pedigree_init_pthreads()
200 {
201  PT_NOTICE("init_pthreads");
202  // Make sure we can write to the trampoline area.
203  Processor::information().getVirtualAddressSpace().setFlags(
204  reinterpret_cast<void *>(Event::getTrampoline()),
206  MemoryCopy(
207  reinterpret_cast<void *>(Event::getSecondaryTrampoline()),
208  reinterpret_cast<void *>(pthread_stub),
209  (reinterpret_cast<uintptr_t>(&pthread_stub_end) -
210  reinterpret_cast<uintptr_t>(pthread_stub)));
211  Processor::information().getVirtualAddressSpace().setFlags(
212  reinterpret_cast<void *>(Event::getTrampoline()),
214 
215  // Make sure the main thread is actually known.
216  Thread *pThread = Processor::information().getCurrentThread();
217  Process *pProcess = pThread->getParent();
218  PosixSubsystem *pSubsystem =
219  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
220  if (!pSubsystem)
221  {
222  ERROR("No subsystem for this process!");
223  return;
224  }
225 
227  pPosixThread->pThread = pThread;
228  pPosixThread->returnValue = 0;
229  pSubsystem->insertThread(pThread->getId(), pPosixThread);
230 }
231 
232 void *posix_pedigree_create_waiter()
233 {
234  PT_NOTICE("posix_pedigree_create_waiter");
235 
236  Process *pProcess =
237  Processor::information().getCurrentThread()->getParent();
238  PosixSubsystem *pSubsystem =
239  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
240  if (!pSubsystem)
241  {
242  ERROR("No subsystem for this process!");
243  return 0;
244  }
245 
246  Semaphore *sem = new Semaphore(0);
247  void *descriptor = pSubsystem->insertThreadWaiter(sem);
248  if (!descriptor)
249  {
250  delete sem;
251  }
252 
253  return descriptor;
254 }
255 
256 int posix_pedigree_thread_wait_for(void *waiter)
257 {
258  PT_NOTICE("posix_pedigree_thread_wait_for");
259 
260  Process *pProcess =
261  Processor::information().getCurrentThread()->getParent();
262  PosixSubsystem *pSubsystem =
263  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
264  if (!pSubsystem)
265  {
266  ERROR("No subsystem for this process!");
267  return -1;
268  }
269 
270  Semaphore *sem = pSubsystem->getThreadWaiter(waiter);
271  if (!sem)
272  {
273  return -1;
274  }
275 
276  // Deadlock detection - don't wait if nothing can wake this waiter.
279  if (pProcess->getNumThreads() <= 1)
280  {
281  SYSCALL_ERROR(Deadlock);
282  return -1;
283  }
284 
285  while (!sem->acquire(1))
286  ;
287 
288  return 0;
289 }
290 
291 int posix_pedigree_thread_trigger(void *waiter)
292 {
293  PT_NOTICE("posix_pedigree_thread_trigger");
294 
295  Process *pProcess =
296  Processor::information().getCurrentThread()->getParent();
297  PosixSubsystem *pSubsystem =
298  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
299  if (!pSubsystem)
300  {
301  ERROR("No subsystem for this process!");
302  return 0;
303  }
304 
305  Semaphore *sem = pSubsystem->getThreadWaiter(waiter);
306  if (!sem)
307  return 0;
308  if (sem->getValue())
309  return 0; // Nothing to wake up.
310 
311  // Wake up a waiter.
312  sem->release();
313  return 1;
314 }
315 
316 void posix_pedigree_destroy_waiter(void *waiter)
317 {
318  PT_NOTICE("posix_pedigree_destroy_waiter");
319 
320  Process *pProcess =
321  Processor::information().getCurrentThread()->getParent();
322  PosixSubsystem *pSubsystem =
323  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
324  if (!pSubsystem)
325  {
326  ERROR("No subsystem for this process!");
327  return;
328  }
329 
330  Semaphore *sem = pSubsystem->getThreadWaiter(waiter);
331  if (!sem)
332  {
333  return;
334  }
335  pSubsystem->removeThreadWaiter(waiter);
336  delete sem;
337 }
338 
339 pid_t posix_gettid()
340 {
341  // Single-threaded process, gettid() returns the PID.
342  Thread *pThread = Processor::information().getCurrentThread();
343  Process *pProcess = pThread->getParent();
344  if (pProcess->getNumThreads() == 1)
345  {
346  return pProcess->getId();
347  }
348 
349  // Otherwise, we return the current thread's ID.
350  return pThread->getId();
351 }
void release()
Definition: Spinlock.cc:273
void pushBack(const T &value)
Definition: List.h:232
Tree< size_t, PosixThreadKey * > m_ThreadData
static uintptr_t getTrampoline()
Definition: Event.cc:66
bool acquire(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
Definition: Semaphore.h:62
size_t getId()
Definition: Process.h:108
void removeThreadWaiter(void *n)
void * insertThreadWaiter(Semaphore *waiter)
T popFront()
Definition: List.h:319
bool acquire(bool recurse=false, bool safe=true)
Definition: Spinlock.cc:43
static ProcessorInformation & information()
Definition: Processor.cc:45
ssize_t getValue()
Definition: Semaphore.cc:318
void insert(const K &key, const E &value)
Definition: Tree.h:173
void release(size_t n=1)
Definition: Semaphore.cc:239
bool addThreadData(size_t key, PosixThreadKey *info)
Definition: Log.h:136
Spinlock & getLock()
Definition: Thread.h:301
A key/value dictionary.
Definition: Tree.h:33
void setStatus(Status s)
Definition: Thread.cc:364
size_t getNumThreads()
Definition: Process.cc:219
void set(size_t n)
PosixThread * getThread(size_t n)
Process * getParent() const
Definition: Thread.h:181
Definition: Thread.h:54
Semaphore * getThreadWaiter(void *n)
#define ERROR(text)
Definition: Log.h:82
size_t lastDataKey
Last data key that was allocated (for the bitmap)
Definition: Log.h:138
size_t getId()
Definition: Thread.h:210
void insertThread(size_t n, PosixThread *thread)
size_t nextDataKey
Next data key available.
static uintptr_t getSecondaryTrampoline()
Definition: Event.cc:72
E lookup(const K &key) const
Definition: Tree.h:192
size_t count() const
Definition: List.h:227