src/thread_pthread.cpp
branchnoai
changeset 9857 7adb6a846add
child 9859 81621c6ba0e9
equal deleted inserted replaced
9856:6a0dcee9f8e4 9857:7adb6a846add
       
     1 /* $Id$ */
       
     2 
       
     3 /** @file thread_pthread.cpp POSIX pthread implementation of Threads. */
       
     4 
       
     5 #include "stdafx.h"
       
     6 #include "thread.h"
       
     7 #include "debug.h"
       
     8 #include "core/alloc_func.hpp"
       
     9 #include <stdlib.h>
       
    10 #include <pthread.h>
       
    11 #include <semaphore.h>
       
    12 #include <unistd.h>
       
    13 
       
    14 struct OTTDThread {
       
    15 	pthread_t thread;
       
    16 };
       
    17 
       
    18 OTTDThread *OTTDCreateThread(OTTDThreadFunc function, void *arg)
       
    19 {
       
    20 	OTTDThread *t = MallocT<OTTDThread>(1);
       
    21 
       
    22 	if (t == NULL) return NULL;
       
    23 
       
    24 	if (pthread_create(&t->thread, NULL, function, arg) == 0) {
       
    25 		return t;
       
    26 	} else {
       
    27 		free(t);
       
    28 		return NULL;
       
    29 	}
       
    30 }
       
    31 
       
    32 void *OTTDJoinThread(OTTDThread *t)
       
    33 {
       
    34 	void* ret;
       
    35 
       
    36 	if (t == NULL) return NULL;
       
    37 
       
    38 	pthread_join(t->thread, &ret);
       
    39 	free(t);
       
    40 	return ret;
       
    41 }
       
    42 
       
    43 void OTTDExitThread()
       
    44 {
       
    45 	pthread_exit(NULL);
       
    46 }
       
    47 
       
    48 
       
    49 /**
       
    50  * POSIX pthread version for ThreadObject.
       
    51  */
       
    52 class ThreadObject_pthread : public ThreadObject {
       
    53 private:
       
    54 	pthread_t m_thr;             ///< System thread identifier.
       
    55 	OTTDThreadFunc m_proc;       ///< External thread procedure.
       
    56 	void     *m_param;           ///< Parameter for the external thread procedure.
       
    57 	bool      m_attached;        ///< True if the ThreadObject was attached to an existing thread.
       
    58 	sem_t     m_sem_start;       ///< Here the new thread waits before it starts.
       
    59 	sem_t     m_sem_stop;        ///< Here the other thread can wait for this thread to end.
       
    60 
       
    61 public:
       
    62 	/**
       
    63 	 * Create a pthread and start it, calling proc(param).
       
    64 	 */
       
    65 	ThreadObject_pthread(OTTDThreadFunc proc, void *param) :
       
    66 		m_thr(0),
       
    67 		m_proc(proc),
       
    68 		m_param(param),
       
    69 		m_attached(false)
       
    70 	{
       
    71 		sem_init(&m_sem_start, 0, 0);
       
    72 		sem_init(&m_sem_stop, 0, 0);
       
    73 
       
    74 		pthread_create(&m_thr, NULL, &stThreadProc, this);
       
    75 		sem_post(&m_sem_start);
       
    76 	}
       
    77 
       
    78 	/**
       
    79 	 * Create a pthread and attach current thread to it.
       
    80 	 */
       
    81 	ThreadObject_pthread() :
       
    82 		m_thr(0),
       
    83 		m_proc(NULL),
       
    84 		m_param(0),
       
    85 		m_attached(true)
       
    86 	{
       
    87 		sem_init(&m_sem_start, 0, 0);
       
    88 		sem_init(&m_sem_stop, 0, 0);
       
    89 
       
    90 		m_thr = pthread_self();
       
    91 	}
       
    92 
       
    93 	/* virtual */ ~ThreadObject_pthread()
       
    94 	{
       
    95 		sem_destroy(&m_sem_stop);
       
    96 		sem_destroy(&m_sem_start);
       
    97 	};
       
    98 
       
    99 	/* virtual */ bool IsRunning()
       
   100 	{
       
   101 		return m_thr != 0;
       
   102 	}
       
   103 
       
   104 	/* virtual */ bool WaitForStop()
       
   105 	{
       
   106 		/* You can't wait on yourself */
       
   107 		assert(!IsCurrent());
       
   108 		/* If the thread is not running, waiting is over */
       
   109 		if (!IsRunning()) return true;
       
   110 
       
   111 		int ret = sem_wait(&m_sem_stop);
       
   112 		if (ret == 0) {
       
   113 			/* We have passed semaphore so increment it again */
       
   114 			sem_post(&m_sem_stop);
       
   115 			return true;
       
   116 		}
       
   117 		return false;
       
   118 	}
       
   119 
       
   120 	/* virtual */ bool IsCurrent()
       
   121 	{
       
   122 		return pthread_self() == m_thr;
       
   123 	}
       
   124 
       
   125 	/* virtual */ uint GetId()
       
   126 	{
       
   127 		return (uint)m_thr;
       
   128 	}
       
   129 
       
   130 private:
       
   131 	/**
       
   132 	 * On thread creation, this function is called, which calls the real startup
       
   133 	 *  function. This to get back into the correct instance again.
       
   134 	 */
       
   135 	static void *stThreadProc(void *thr)
       
   136 	{
       
   137 		return ((ThreadObject_pthread*)thr)->ThreadProc();
       
   138 	}
       
   139 
       
   140 	/**
       
   141 	 * A new thread is created, and this function is called. Call the custom
       
   142 	 *  function of the creator of the thread.
       
   143 	 */
       
   144 	void *ThreadProc()
       
   145 	{
       
   146 		/* The new thread stops here so the calling thread can complete pthread_create() call */
       
   147 		sem_wait(&m_sem_start);
       
   148 
       
   149 		/* Call the proc of the creator to continue this thread */
       
   150 		try {
       
   151 			m_proc(m_param);
       
   152 		} catch (...) {
       
   153 			DEBUG(misc, 0, "Exception in thread %u!", GetId());
       
   154 		}
       
   155 		/* The thread died, so we are no longer valid */
       
   156 		m_thr = 0;
       
   157 
       
   158 		/* Notify threads waiting for our completion */
       
   159 		sem_post(&m_sem_stop);
       
   160 		return NULL;
       
   161 	}
       
   162 };
       
   163 
       
   164 /* static */ ThreadObject *ThreadObject::New(OTTDThreadFunc proc, void *param)
       
   165 {
       
   166 	return new ThreadObject_pthread(proc, param);
       
   167 }
       
   168 
       
   169 /* static */ ThreadObject *ThreadObject::AttachCurrent()
       
   170 {
       
   171 	return new ThreadObject_pthread();
       
   172 }
       
   173 
       
   174 /* static */ uint ThreadObject::CurrentId()
       
   175 {
       
   176 	return (uint)pthread_self();
       
   177 }
       
   178 
       
   179 
       
   180 /**
       
   181  * POSIX pthread version of ThreadSemaphore.
       
   182  */
       
   183 class ThreadSemaphore_pthread : public ThreadSemaphore {
       
   184 private:
       
   185 	sem_t m_sem;
       
   186 
       
   187 public:
       
   188 	ThreadSemaphore_pthread()
       
   189 	{
       
   190 		sem_init(&m_sem, 0, 0);
       
   191 	}
       
   192 
       
   193 	/* virtual */ ~ThreadSemaphore_pthread()
       
   194 	{
       
   195 		sem_destroy(&m_sem);
       
   196 	}
       
   197 
       
   198 	/* virtual */ void Set()
       
   199 	{
       
   200 		int val = 0;
       
   201 		if (sem_getvalue(&m_sem, &val) == 0 && val == 0) sem_post(&m_sem);
       
   202 	}
       
   203 
       
   204 	/* virtual */ void Wait()
       
   205 	{
       
   206 		sem_wait(&m_sem);
       
   207 	}
       
   208 };
       
   209 
       
   210 /* static */ ThreadSemaphore *ThreadSemaphore::New()
       
   211 {
       
   212 	return new ThreadSemaphore_pthread();
       
   213 }