src/thread_pthread.cpp
branchNewGRF_ports
changeset 10211 c1391c8ed5c6
child 10375 947e542f2bfc
child 10724 68a692eacf22
equal deleted inserted replaced
10210:a2131f7a315d 10211:c1391c8ed5c6
       
     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 /**
       
    15  * POSIX pthread version for ThreadObject.
       
    16  */
       
    17 class ThreadObject_pthread : public ThreadObject {
       
    18 private:
       
    19 	pthread_t m_thr;             ///< System thread identifier.
       
    20 	OTTDThreadFunc m_proc;       ///< External thread procedure.
       
    21 	void     *m_param;           ///< Parameter for the external thread procedure.
       
    22 	bool      m_attached;        ///< True if the ThreadObject was attached to an existing thread.
       
    23 	sem_t     m_sem_start;       ///< Here the new thread waits before it starts.
       
    24 	sem_t     m_sem_stop;        ///< Here the other thread can wait for this thread to end.
       
    25 
       
    26 public:
       
    27 	/**
       
    28 	 * Create a pthread and start it, calling proc(param).
       
    29 	 */
       
    30 	ThreadObject_pthread(OTTDThreadFunc proc, void *param) :
       
    31 		m_thr(0),
       
    32 		m_proc(proc),
       
    33 		m_param(param),
       
    34 		m_attached(false)
       
    35 	{
       
    36 		sem_init(&m_sem_start, 0, 0);
       
    37 		sem_init(&m_sem_stop, 0, 0);
       
    38 
       
    39 		pthread_create(&m_thr, NULL, &stThreadProc, this);
       
    40 		sem_post(&m_sem_start);
       
    41 	}
       
    42 
       
    43 	/**
       
    44 	 * Create a pthread and attach current thread to it.
       
    45 	 */
       
    46 	ThreadObject_pthread() :
       
    47 		m_thr(0),
       
    48 		m_proc(NULL),
       
    49 		m_param(0),
       
    50 		m_attached(true)
       
    51 	{
       
    52 		sem_init(&m_sem_start, 0, 0);
       
    53 		sem_init(&m_sem_stop, 0, 0);
       
    54 
       
    55 		m_thr = pthread_self();
       
    56 	}
       
    57 
       
    58 	/* virtual */ ~ThreadObject_pthread()
       
    59 	{
       
    60 		sem_destroy(&m_sem_stop);
       
    61 		sem_destroy(&m_sem_start);
       
    62 	};
       
    63 
       
    64 	/* virtual */ bool IsRunning()
       
    65 	{
       
    66 		return m_thr != 0;
       
    67 	}
       
    68 
       
    69 	/* virtual */ bool WaitForStop()
       
    70 	{
       
    71 		/* You can't wait on yourself */
       
    72 		assert(!IsCurrent());
       
    73 		/* If the thread is not running, waiting is over */
       
    74 		if (!IsRunning()) return true;
       
    75 
       
    76 		int ret = sem_wait(&m_sem_stop);
       
    77 		if (ret == 0) {
       
    78 			/* We have passed semaphore so increment it again */
       
    79 			sem_post(&m_sem_stop);
       
    80 			return true;
       
    81 		}
       
    82 		return false;
       
    83 	}
       
    84 
       
    85 	/* virtual */ bool Exit()
       
    86 	{
       
    87 		/* You can only exit yourself */
       
    88 		assert(IsCurrent());
       
    89 		/* If the thread is not running, we are already closed */
       
    90 		if (!IsRunning()) return false;
       
    91 
       
    92 		/* For now we terminate by throwing an error, gives much cleaner cleanup */
       
    93 		throw 0;
       
    94 	}
       
    95 
       
    96 	/* virtual */ void *Join()
       
    97 	{
       
    98 		/* You cannot join yourself */
       
    99 		assert(!IsCurrent());
       
   100 
       
   101 		void *ret;
       
   102 		pthread_join(m_thr, &ret);
       
   103 		m_thr = 0;
       
   104 
       
   105 		return ret;
       
   106 	}
       
   107 
       
   108 	/* virtual */ bool IsCurrent()
       
   109 	{
       
   110 		return pthread_self() == m_thr;
       
   111 	}
       
   112 
       
   113 	/* virtual */ uint GetId()
       
   114 	{
       
   115 		return (uint)m_thr;
       
   116 	}
       
   117 
       
   118 private:
       
   119 	/**
       
   120 	 * On thread creation, this function is called, which calls the real startup
       
   121 	 *  function. This to get back into the correct instance again.
       
   122 	 */
       
   123 	static void *stThreadProc(void *thr)
       
   124 	{
       
   125 		return ((ThreadObject_pthread *)thr)->ThreadProc();
       
   126 	}
       
   127 
       
   128 	/**
       
   129 	 * A new thread is created, and this function is called. Call the custom
       
   130 	 *  function of the creator of the thread.
       
   131 	 */
       
   132 	void *ThreadProc()
       
   133 	{
       
   134 		/* The new thread stops here so the calling thread can complete pthread_create() call */
       
   135 		sem_wait(&m_sem_start);
       
   136 
       
   137 		/* Call the proc of the creator to continue this thread */
       
   138 		try {
       
   139 			m_proc(m_param);
       
   140 		} catch (...) {
       
   141 		}
       
   142 
       
   143 		/* Notify threads waiting for our completion */
       
   144 		sem_post(&m_sem_stop);
       
   145 
       
   146 		return NULL;
       
   147 	}
       
   148 };
       
   149 
       
   150 /* static */ ThreadObject *ThreadObject::New(OTTDThreadFunc proc, void *param)
       
   151 {
       
   152 	return new ThreadObject_pthread(proc, param);
       
   153 }
       
   154 
       
   155 /* static */ ThreadObject *ThreadObject::AttachCurrent()
       
   156 {
       
   157 	return new ThreadObject_pthread();
       
   158 }
       
   159 
       
   160 /* static */ uint ThreadObject::CurrentId()
       
   161 {
       
   162 	return (uint)pthread_self();
       
   163 }
       
   164 
       
   165 
       
   166 /**
       
   167  * POSIX pthread version of ThreadSemaphore.
       
   168  */
       
   169 class ThreadSemaphore_pthread : public ThreadSemaphore {
       
   170 private:
       
   171 	sem_t m_sem;
       
   172 
       
   173 public:
       
   174 	ThreadSemaphore_pthread()
       
   175 	{
       
   176 		sem_init(&m_sem, 0, 0);
       
   177 	}
       
   178 
       
   179 	/* virtual */ ~ThreadSemaphore_pthread()
       
   180 	{
       
   181 		sem_destroy(&m_sem);
       
   182 	}
       
   183 
       
   184 	/* virtual */ void Set()
       
   185 	{
       
   186 		int val = 0;
       
   187 		if (sem_getvalue(&m_sem, &val) == 0 && val == 0) sem_post(&m_sem);
       
   188 	}
       
   189 
       
   190 	/* virtual */ void Wait()
       
   191 	{
       
   192 		sem_wait(&m_sem);
       
   193 	}
       
   194 };
       
   195 
       
   196 /* static */ ThreadSemaphore *ThreadSemaphore::New()
       
   197 {
       
   198 	return new ThreadSemaphore_pthread();
       
   199 }