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