1 /*****************************************************************
2 |
3 | Neptune - Threads :: Posix Implementation
4 |
5 | (c) 2001-2002 Gilles Boccon-Gibod
6 | Author: Gilles Boccon-Gibod (bok@bok.net)
7 |
8 ****************************************************************/
9
10 /*----------------------------------------------------------------------
11 | includes
12 +---------------------------------------------------------------------*/
13 #if defined(__SYMBIAN32__)
14 #include <stdio.h>
15 #endif
16 #include <pthread.h>
17 #include <unistd.h>
18 #include <time.h>
19 #include <sys/time.h>
20 #include <errno.h>
21
22 #include "NptConfig.h"
23 #include "NptTypes.h"
24 #include "NptThreads.h"
25 #include "NptLogging.h"
26 #include "NptTime.h"
27 #include "NptSystem.h"
28 #include "NptUtils.h"
29 #include "NptAutoreleasePool.h"
30
31 /*----------------------------------------------------------------------
32 | logging
33 +---------------------------------------------------------------------*/
34 NPT_SET_LOCAL_LOGGER("neptune.threads.posix")
35
36 /*----------------------------------------------------------------------
37 | NPT_PosixMutex
38 +---------------------------------------------------------------------*/
39 class NPT_PosixMutex : public NPT_MutexInterface
40 {
41 public:
42 // methods
43 NPT_PosixMutex(bool recursive = false);
44 virtual ~NPT_PosixMutex();
45
46 // NPT_Mutex methods
47 virtual NPT_Result Lock();
48 virtual NPT_Result Unlock();
49
50 private:
51 // members
52 pthread_mutex_t m_Mutex;
53 };
54
55 /*----------------------------------------------------------------------
56 | NPT_PosixMutex::NPT_PosixMutex
57 +---------------------------------------------------------------------*/
NPT_PosixMutex(bool recursive)58 NPT_PosixMutex::NPT_PosixMutex(bool recursive)
59 {
60 // Recursive by default
61 pthread_mutexattr_t attr;
62
63 if (recursive) {
64 pthread_mutexattr_init(&attr);
65 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
66 }
67
68 pthread_mutex_init(&m_Mutex, recursive?&attr:NULL);
69 }
70
71 /*----------------------------------------------------------------------
72 | NPT_PosixMutex::~NPT_PosixMutex
73 +---------------------------------------------------------------------*/
~NPT_PosixMutex()74 NPT_PosixMutex::~NPT_PosixMutex()
75 {
76 pthread_mutex_destroy(&m_Mutex);
77 }
78
79 /*----------------------------------------------------------------------
80 | NPT_PosixMutex::Lock
81 +---------------------------------------------------------------------*/
82 NPT_Result
Lock()83 NPT_PosixMutex::Lock()
84 {
85 pthread_mutex_lock(&m_Mutex);
86 return NPT_SUCCESS;
87 }
88
89 /*----------------------------------------------------------------------
90 | NPT_PosixMutex::Unlock
91 +---------------------------------------------------------------------*/
92 NPT_Result
Unlock()93 NPT_PosixMutex::Unlock()
94 {
95 pthread_mutex_unlock(&m_Mutex);
96 return NPT_SUCCESS;
97 }
98
99 /*----------------------------------------------------------------------
100 | NPT_Mutex::NPT_Mutex
101 +---------------------------------------------------------------------*/
NPT_Mutex(bool recursive)102 NPT_Mutex::NPT_Mutex(bool recursive)
103 {
104 m_Delegate = new NPT_PosixMutex(recursive);
105 }
106
107 /*----------------------------------------------------------------------
108 | NPT_PosixSharedVariable
109 +---------------------------------------------------------------------*/
110 class NPT_PosixSharedVariable : public NPT_SharedVariableInterface
111 {
112 public:
113 // methods
114 NPT_PosixSharedVariable(int value);
115 ~NPT_PosixSharedVariable();
116 void SetValue(int value);
117 int GetValue();
118 NPT_Result WaitUntilEquals(int value, NPT_Timeout timeout);
119 NPT_Result WaitWhileEquals(int value, NPT_Timeout timeout);
120
121 private:
122 // members
123 volatile int m_Value;
124 pthread_mutex_t m_Mutex;
125 pthread_cond_t m_Condition;
126 };
127
128 /*----------------------------------------------------------------------
129 | NPT_PosixSharedVariable::NPT_PosixSharedVariable
130 +---------------------------------------------------------------------*/
NPT_PosixSharedVariable(int value)131 NPT_PosixSharedVariable::NPT_PosixSharedVariable(int value) :
132 m_Value(value)
133 {
134 pthread_mutex_init(&m_Mutex, NULL);
135 pthread_cond_init(&m_Condition, NULL);
136 }
137
138 /*----------------------------------------------------------------------
139 | NPT_PosixSharedVariable::~NPT_PosixSharedVariable
140 +---------------------------------------------------------------------*/
~NPT_PosixSharedVariable()141 NPT_PosixSharedVariable::~NPT_PosixSharedVariable()
142 {
143 pthread_cond_destroy(&m_Condition);
144 pthread_mutex_destroy(&m_Mutex);
145 }
146
147 /*----------------------------------------------------------------------
148 | NPT_PosixSharedVariable::SetValue
149 +---------------------------------------------------------------------*/
150 void
SetValue(int value)151 NPT_PosixSharedVariable::SetValue(int value)
152 {
153 pthread_mutex_lock(&m_Mutex);
154 m_Value = value;
155 pthread_cond_broadcast(&m_Condition);
156 pthread_mutex_unlock(&m_Mutex);
157 }
158
159 /*----------------------------------------------------------------------
160 | NPT_PosixSharedVariable::GetValue
161 +---------------------------------------------------------------------*/
162 int
GetValue()163 NPT_PosixSharedVariable::GetValue()
164 {
165 // we assume that int read/write are atomic on the platform
166 return m_Value;
167 }
168
169 /*----------------------------------------------------------------------
170 | NPT_PosixSharedVariable::WaitUntilEquals
171 +---------------------------------------------------------------------*/
172 NPT_Result
WaitUntilEquals(int value,NPT_Timeout timeout)173 NPT_PosixSharedVariable::WaitUntilEquals(int value, NPT_Timeout timeout)
174 {
175 NPT_Result result = NPT_SUCCESS;
176 struct timespec timed;
177
178 if (timeout != NPT_TIMEOUT_INFINITE) {
179 // get current time from system
180 struct timeval now;
181 if (gettimeofday(&now, NULL)) {
182 return NPT_FAILURE;
183 }
184
185 now.tv_usec += timeout * 1000;
186 if (now.tv_usec >= 1000000) {
187 now.tv_sec += now.tv_usec / 1000000;
188 now.tv_usec = now.tv_usec % 1000000;
189 }
190
191 // setup timeout
192 timed.tv_sec = now.tv_sec;
193 timed.tv_nsec = now.tv_usec * 1000;
194 }
195
196 pthread_mutex_lock(&m_Mutex);
197 while (value != m_Value) {
198 if (timeout == NPT_TIMEOUT_INFINITE) {
199 pthread_cond_wait(&m_Condition, &m_Mutex);
200 } else {
201 int wait_res = pthread_cond_timedwait(&m_Condition, &m_Mutex, &timed);
202 if (wait_res == ETIMEDOUT) {
203 result = NPT_ERROR_TIMEOUT;
204 break;
205 }
206 }
207 }
208 pthread_mutex_unlock(&m_Mutex);
209
210 return result;
211 }
212
213 /*----------------------------------------------------------------------
214 | NPT_PosixSharedVariable::WaitWhileEquals
215 +---------------------------------------------------------------------*/
216 NPT_Result
WaitWhileEquals(int value,NPT_Timeout timeout)217 NPT_PosixSharedVariable::WaitWhileEquals(int value, NPT_Timeout timeout)
218 {
219 NPT_Result result = NPT_SUCCESS;
220 struct timespec timed;
221
222 if (timeout != NPT_TIMEOUT_INFINITE) {
223 // get current time from system
224 struct timeval now;
225 if (gettimeofday(&now, NULL)) {
226 return NPT_FAILURE;
227 }
228
229 now.tv_usec += timeout * 1000;
230 if (now.tv_usec >= 1000000) {
231 now.tv_sec += now.tv_usec / 1000000;
232 now.tv_usec = now.tv_usec % 1000000;
233 }
234
235 // setup timeout
236 timed.tv_sec = now.tv_sec;
237 timed.tv_nsec = now.tv_usec * 1000;
238 }
239
240 pthread_mutex_lock(&m_Mutex);
241 while (value == m_Value) {
242 if (timeout == NPT_TIMEOUT_INFINITE) {
243 pthread_cond_wait(&m_Condition, &m_Mutex);
244 } else {
245 int wait_res = pthread_cond_timedwait(&m_Condition, &m_Mutex, &timed);
246 if (wait_res == ETIMEDOUT) {
247 result = NPT_ERROR_TIMEOUT;
248 break;
249 }
250 }
251 }
252 pthread_mutex_unlock(&m_Mutex);
253
254 return result;
255 }
256
257 /*----------------------------------------------------------------------
258 | NPT_SharedVariable::NPT_SharedVariable
259 +---------------------------------------------------------------------*/
NPT_SharedVariable(int value)260 NPT_SharedVariable::NPT_SharedVariable(int value)
261 {
262 m_Delegate = new NPT_PosixSharedVariable(value);
263 }
264
265 /*----------------------------------------------------------------------
266 | NPT_PosixAtomicVariable
267 +---------------------------------------------------------------------*/
268 class NPT_PosixAtomicVariable : public NPT_AtomicVariableInterface
269 {
270 public:
271 // methods
272 NPT_PosixAtomicVariable(int value);
273 ~NPT_PosixAtomicVariable();
274 int Increment();
275 int Decrement();
276 int GetValue();
277 void SetValue(int value);
278
279 private:
280 // members
281 volatile int m_Value;
282 pthread_mutex_t m_Mutex;
283 };
284
285 /*----------------------------------------------------------------------
286 | NPT_PosixAtomicVariable::NPT_PosixAtomicVariable
287 +---------------------------------------------------------------------*/
NPT_PosixAtomicVariable(int value)288 NPT_PosixAtomicVariable::NPT_PosixAtomicVariable(int value) :
289 m_Value(value)
290 {
291 pthread_mutex_init(&m_Mutex, NULL);
292 }
293
294 /*----------------------------------------------------------------------
295 | NPT_PosixAtomicVariable::~NPT_PosixAtomicVariable
296 +---------------------------------------------------------------------*/
~NPT_PosixAtomicVariable()297 NPT_PosixAtomicVariable::~NPT_PosixAtomicVariable()
298 {
299 pthread_mutex_destroy(&m_Mutex);
300 }
301
302 /*----------------------------------------------------------------------
303 | NPT_PosixAtomicVariable::Increment
304 +---------------------------------------------------------------------*/
305 int
Increment()306 NPT_PosixAtomicVariable::Increment()
307 {
308 int value;
309
310 pthread_mutex_lock(&m_Mutex);
311 value = ++m_Value;
312 pthread_mutex_unlock(&m_Mutex);
313
314 return value;
315 }
316
317 /*----------------------------------------------------------------------
318 | NPT_PosixAtomicVariable::Decrement
319 +---------------------------------------------------------------------*/
320 int
Decrement()321 NPT_PosixAtomicVariable::Decrement()
322 {
323 int value;
324
325 pthread_mutex_lock(&m_Mutex);
326 value = --m_Value;
327 pthread_mutex_unlock(&m_Mutex);
328
329 return value;
330 }
331
332 /*----------------------------------------------------------------------
333 | NPT_PosixAtomicVariable::GetValue
334 +---------------------------------------------------------------------*/
335 int
GetValue()336 NPT_PosixAtomicVariable::GetValue()
337 {
338 // we assume that int read/write are atomic on the platform
339 return m_Value;
340 }
341
342 /*----------------------------------------------------------------------
343 | NPT_PosixAtomicVariable::SetValue
344 +---------------------------------------------------------------------*/
345 void
SetValue(int value)346 NPT_PosixAtomicVariable::SetValue(int value)
347 {
348 pthread_mutex_lock(&m_Mutex);
349 m_Value = value;
350 pthread_mutex_unlock(&m_Mutex);
351 }
352
353 /*----------------------------------------------------------------------
354 | NPT_AtomicVariable::NPT_AtomicVariable
355 +---------------------------------------------------------------------*/
NPT_AtomicVariable(int value)356 NPT_AtomicVariable::NPT_AtomicVariable(int value)
357 {
358 m_Delegate = new NPT_PosixAtomicVariable(value);
359 }
360
361 /*----------------------------------------------------------------------
362 | NPT_PosixThread
363 +---------------------------------------------------------------------*/
364 class NPT_PosixThread : public NPT_ThreadInterface
365 {
366 public:
367 // methods
368 NPT_PosixThread(NPT_Thread* delegator,
369 NPT_Runnable& target,
370 bool detached);
371 ~NPT_PosixThread();
372 NPT_Result Start();
373 NPT_Result Wait(NPT_Timeout timeout = NPT_TIMEOUT_INFINITE);
374 NPT_Result CancelBlockerSocket();
375 NPT_Result SetPriority(int priority);
376 NPT_Result GetPriority(int& priority);
377
378 // class methods
379 static NPT_Result GetPriority(NPT_Thread::ThreadId thread_id, int& priority);
380 static NPT_Result SetPriority(NPT_Thread::ThreadId thread_id, int priority);
381
382 private:
383 // methods
384 static void* EntryPoint(void* argument);
385
386 // NPT_Runnable methods
387 void Run();
388
389 // NPT_Interruptible methods
Interrupt()390 NPT_Result Interrupt() { return NPT_ERROR_NOT_IMPLEMENTED; }
391
392 // members
393 NPT_Thread* m_Delegator;
394 NPT_Runnable& m_Target;
395 bool m_Detached;
396 pthread_t m_ThreadId;
397 bool m_Joined;
398 NPT_PosixMutex m_JoinLock;
399 NPT_SharedVariable m_Done;
400 };
401
402 /*----------------------------------------------------------------------
403 | NPT_PosixThread::NPT_PosixThread
404 +---------------------------------------------------------------------*/
NPT_PosixThread(NPT_Thread * delegator,NPT_Runnable & target,bool detached)405 NPT_PosixThread::NPT_PosixThread(NPT_Thread* delegator,
406 NPT_Runnable& target,
407 bool detached) :
408 m_Delegator(delegator),
409 m_Target(target),
410 m_Detached(detached),
411 m_ThreadId(0),
412 m_Joined(false)
413 {
414 NPT_LOG_FINER("NPT_PosixThread::NPT_PosixThread");
415 m_Done.SetValue(0);
416 }
417
418 /*----------------------------------------------------------------------
419 | NPT_PosixThread::~NPT_PosixThread
420 +---------------------------------------------------------------------*/
~NPT_PosixThread()421 NPT_PosixThread::~NPT_PosixThread()
422 {
423 //NPT_LOG_FINE_1("NPT_PosixThread::~NPT_PosixThread %lld\n", (NPT_Thread::ThreadId)m_ThreadId);
424
425 if (!m_Detached) {
426 // we're not detached, and not in the Run() method, so we need to
427 // wait until the thread is done
428 Wait();
429 }
430 }
431
432 /*----------------------------------------------------------------------
433 | NPT_Thread::GetCurrentThreadId
434 +---------------------------------------------------------------------*/
435 NPT_Thread::ThreadId
GetCurrentThreadId()436 NPT_Thread::GetCurrentThreadId()
437 {
438 pthread_t pid = pthread_self();
439 return (NPT_Thread::ThreadId)pid;
440 }
441
442 /*----------------------------------------------------------------------
443 | NPT_Thread::SetCurrentThreadPriority
444 +---------------------------------------------------------------------*/
445 NPT_Result
SetCurrentThreadPriority(int priority)446 NPT_Thread::SetCurrentThreadPriority(int priority)
447 {
448 return NPT_PosixThread::SetPriority(GetCurrentThreadId(), priority);
449 }
450
451 /*----------------------------------------------------------------------
452 | NPT_Thread::GetCurrentThreadPriority
453 +---------------------------------------------------------------------*/
454 NPT_Result
GetCurrentThreadPriority(int & priority)455 NPT_Thread::GetCurrentThreadPriority(int& priority)
456 {
457 return NPT_PosixThread::GetPriority(GetCurrentThreadId(), priority);
458 }
459
460 /*----------------------------------------------------------------------
461 | NPT_PosixThread::EntryPoint
462 +---------------------------------------------------------------------*/
463 void*
EntryPoint(void * argument)464 NPT_PosixThread::EntryPoint(void* argument)
465 {
466 NPT_PosixThread* thread = reinterpret_cast<NPT_PosixThread*>(argument);
467
468 NPT_LOG_FINER("NPT_PosixThread::EntryPoint - in =======================");
469
470 // ensure there is the top level autorelease pool for each thread
471 NPT_AutoreleasePool pool;
472
473 // get the thread ID from this context, because m_ThreadId may not yet
474 // have been set by the parent thread in the Start() method
475 thread->m_ThreadId = pthread_self();
476
477 // set random seed per thread
478 NPT_TimeStamp now;
479 NPT_System::GetCurrentTimeStamp(now);
480 NPT_System::SetRandomSeed((unsigned int)(now.ToNanos() + (long)thread->m_ThreadId));
481
482 // run the thread
483 thread->Run();
484
485 // Logging here will cause a crash on exit because LogManager may already be destroyed
486 //NPT_LOG_FINE("NPT_PosixThread::EntryPoint - out ======================");
487
488 // we're done with the thread object
489 // if we're detached, we need to delete ourselves
490 if (thread->m_Detached) {
491 delete thread->m_Delegator;
492 } else {
493 // notify we're done
494 thread->m_Done.SetValue(1);
495 }
496
497 // done
498 return NULL;
499 }
500
501 /*----------------------------------------------------------------------
502 | NPT_PosixThread::Start
503 +---------------------------------------------------------------------*/
504 NPT_Result
Start()505 NPT_PosixThread::Start()
506 {
507 NPT_LOG_FINER("NPT_PosixThread::Start - creating thread");
508
509 // reset values
510 m_Joined = false;
511 m_ThreadId = 0;
512 m_Done.SetValue(0);
513
514 pthread_attr_t *attributes = NULL;
515
516 #if defined(NPT_CONFIG_THREAD_STACK_SIZE) && NPT_CONFIG_THREAD_STACK_SIZE
517 pthread_attr_t stack_size_attributes;
518 pthread_attr_init(&stack_size_attributes);
519 pthread_attr_setstacksize(&stack_size_attributes, NPT_CONFIG_THREAD_STACK_SIZE);
520 attributes = &stack_size_attributes;
521 #endif
522
523 // use local copies of some of the object's members, because for
524 // detached threads, the object instance may have deleted itself
525 // before the pthread_create() function returns
526 bool detached = m_Detached;
527
528 // reset the joined flag
529 m_Joined = false;
530
531 // create the native thread
532 pthread_t thread_id;
533 int result = pthread_create(&thread_id, attributes, EntryPoint,
534 static_cast<NPT_PosixThread*>(this));
535 NPT_LOG_FINER_2("NPT_PosixThread::Start - id = %p, res=%d",
536 (void*)thread_id, result);
537 if (result != 0) {
538 // failed
539 return NPT_ERROR_ERRNO(result);
540 } else {
541 // detach the thread if we're not joinable
542 if (detached) {
543 pthread_detach(thread_id);
544 } else {
545 // store the thread ID (NOTE: this is also done by the thread Run() method
546 // but it is necessary to do it from both contexts, because we don't know
547 // which one will need it first.)
548 m_ThreadId = thread_id;
549 }
550 return NPT_SUCCESS;
551 }
552 }
553
554 /*----------------------------------------------------------------------
555 | NPT_PosixThread::Run
556 +---------------------------------------------------------------------*/
557 void
Run()558 NPT_PosixThread::Run()
559 {
560 m_Target.Run();
561 }
562
563 /*----------------------------------------------------------------------
564 | NPT_PosixThread::Wait
565 +---------------------------------------------------------------------*/
566 NPT_Result
Wait(NPT_Timeout timeout)567 NPT_PosixThread::Wait(NPT_Timeout timeout /* = NPT_TIMEOUT_INFINITE */)
568 {
569 void* return_value;
570 int result;
571
572 // check that we're not detached
573 if (m_ThreadId == 0 || m_Detached) {
574 return NPT_FAILURE;
575 }
576
577 // wait for the thread to finish
578 m_JoinLock.Lock();
579 if (m_Joined) {
580 result = 0;
581 } else {
582 if (timeout != NPT_TIMEOUT_INFINITE) {
583 result = m_Done.WaitUntilEquals(1, timeout);
584 if (NPT_FAILED(result)) {
585 result = -1;
586 goto timedout;
587 }
588 }
589
590 result = pthread_join(m_ThreadId, &return_value);
591 m_Joined = true;
592 }
593
594 timedout:
595 m_JoinLock.Unlock();
596 if (result != 0) {
597 return NPT_FAILURE;
598 } else {
599 return NPT_SUCCESS;
600 }
601 }
602
603 /*----------------------------------------------------------------------
604 | NPT_PosixThread::CancelBlockerSocket
605 +---------------------------------------------------------------------*/
606 NPT_Result
CancelBlockerSocket()607 NPT_PosixThread::CancelBlockerSocket()
608 {
609 return NPT_Socket::CancelBlockerSocket((NPT_Thread::ThreadId)m_ThreadId);
610 }
611
612 /*----------------------------------------------------------------------
613 | NPT_PosixThread::SetPriority
614 +---------------------------------------------------------------------*/
615 NPT_Result
SetPriority(int priority)616 NPT_PosixThread::SetPriority(int priority)
617 {
618 // check that we're started
619 if (m_ThreadId == 0) {
620 return NPT_FAILURE;
621 }
622
623 return NPT_PosixThread::SetPriority((NPT_Thread::ThreadId)m_ThreadId, priority);
624 }
625
626 /*----------------------------------------------------------------------
627 | NPT_PosixThread::SetPriority
628 +---------------------------------------------------------------------*/
629 NPT_Result
SetPriority(NPT_Thread::ThreadId thread_id,int priority)630 NPT_PosixThread::SetPriority(NPT_Thread::ThreadId thread_id, int priority)
631 {
632 // check that we're started
633 if (thread_id == 0) {
634 return NPT_FAILURE;
635 }
636
637 /* sched_priority will be the priority of the thread */
638 struct sched_param sp;
639 int policy;
640 int result = pthread_getschedparam((pthread_t)thread_id, &policy, &sp);
641
642 NPT_LOG_FINER_3("Current thread policy: %d, priority: %d, new priority: %d",
643 policy, sp.sched_priority, priority);
644 NPT_LOG_FINER_4("Thread max(SCHED_OTHER): %d, max(SCHED_RR): %d \
645 min(SCHED_OTHER): %d, min(SCHED_RR): %d",
646 sched_get_priority_max(SCHED_OTHER),
647 sched_get_priority_max(SCHED_RR),
648 sched_get_priority_min(SCHED_OTHER),
649 sched_get_priority_min(SCHED_RR));
650
651 sp.sched_priority = priority;
652
653 /*
654 if (sp.sched_priority <= 0)
655 sp.sched_priority += sched_get_priority_max (policy = SCHED_OTHER);
656 else
657 sp.sched_priority += sched_get_priority_min (policy = SCHED_RR);
658 */
659
660 /* scheduling parameters of target thread */
661 result = pthread_setschedparam((pthread_t)thread_id, policy, &sp);
662
663 return (result==0)?NPT_SUCCESS:NPT_ERROR_ERRNO(result);
664 }
665
666 /*----------------------------------------------------------------------
667 | NPT_PosixThread::GetPriority
668 +---------------------------------------------------------------------*/
669 NPT_Result
GetPriority(int & priority)670 NPT_PosixThread::GetPriority(int& priority)
671 {
672 // check that we're started
673 if (m_ThreadId == 0) {
674 return NPT_FAILURE;
675 }
676
677 return NPT_PosixThread::GetPriority((NPT_Thread::ThreadId)m_ThreadId, priority);
678 }
679
680 /*----------------------------------------------------------------------
681 | NPT_PosixThread::GetPriority
682 +---------------------------------------------------------------------*/
683 NPT_Result
GetPriority(NPT_Thread::ThreadId thread_id,int & priority)684 NPT_PosixThread::GetPriority(NPT_Thread::ThreadId thread_id, int& priority)
685 {
686 // check that we're started
687 if (thread_id == 0) {
688 return NPT_FAILURE;
689 }
690
691 struct sched_param sp;
692 int policy;
693
694 int result = pthread_getschedparam((pthread_t)thread_id, &policy, &sp);
695 NPT_LOG_FINER_1("Current thread priority: %d", sp.sched_priority);
696
697 priority = sp.sched_priority;
698 return (result==0)?NPT_SUCCESS:NPT_ERROR_ERRNO(result);
699 }
700
701 /*----------------------------------------------------------------------
702 | NPT_Thread::NPT_Thread
703 +---------------------------------------------------------------------*/
NPT_Thread(bool detached)704 NPT_Thread::NPT_Thread(bool detached)
705 {
706 m_Delegate = new NPT_PosixThread(this, *this, detached);
707 }
708
709 /*----------------------------------------------------------------------
710 | NPT_Thread::NPT_Thread
711 +---------------------------------------------------------------------*/
NPT_Thread(NPT_Runnable & target,bool detached)712 NPT_Thread::NPT_Thread(NPT_Runnable& target, bool detached)
713 {
714 m_Delegate = new NPT_PosixThread(this, target, detached);
715 }
716
717