1 /*******************************************************************************
2 * Copyright (C) 2004-2008 Intel Corp. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * - Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 *
10 * - Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * - Neither the name of Intel Corp. nor the names of its
15 * contributors may be used to endorse or promote products derived from this
16 * software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL Intel Corp. OR THE CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 *******************************************************************************/
30
31 //////////////////////////////////////////////////////////////////////////
32 // ThreadLinux.cpp
33 //
34 // This file contains the linux implementation of the Thread class
35 ///////////////////////////////////////////////////////////////////////////
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39 #include "Thread.h"
40 #include <pthread.h>
41 #include <sys/time.h>
42 #include <cerrno>
43 #include <cstdio>
44
45
46 class OSThread
47 {
48 public:
49 pthread_t _handle;
50 pthread_cond_t _cond;
51 pthread_mutex_t _mut;
52 bool _running;
53 static void *threadFunc(void * thread_p);
54 };
55
56
threadFunc(void * thread_p)57 void *OSThread::threadFunc(void *thread_p)
58 {
59 if (thread_p) {
60 Thread *t = (Thread*)thread_p;
61 //printf("@@@@ OSThread::threadFunc (%p)\n", t->_osThread);
62 t->run();
63 //printf("@@@@ OSThread::threadFunc (%p) after run\n", t->_osThread);
64 pthread_mutex_lock(&t->_osThread->_mut);
65 t->_osThread->_running = false;
66 //printf("@@@@ OSThread::threadFunc setting signal\n");
67 pthread_cond_signal(&t->_osThread->_cond);
68 pthread_mutex_unlock(&t->_osThread->_mut);
69 }
70 return (void *)0;
71 }
72
Thread(CallbackFunction func_p,void * param_p)73 Thread::Thread(CallbackFunction func_p, void* param_p)
74 {
75 _osThread = new OSThread;
76 _osThread->_handle = 0;
77 _osThread->_running = false;
78 pthread_mutex_init(&_osThread->_mut, NULL);
79 pthread_cond_init(&_osThread->_cond, NULL);
80 _func = func_p;
81 _param = param_p;
82 }
83
~Thread()84 Thread::~Thread()
85 {
86 pthread_cond_destroy(&_osThread->_cond);
87 pthread_mutex_destroy(&_osThread->_mut);
88 delete _osThread;
89 }
90
currentThread()91 unsigned long Thread::currentThread()
92 {
93 return pthread_self();
94 }
95
wait(unsigned long msecs_p) const96 bool Thread::wait(unsigned long msecs_p) const
97 {
98 int retcode = 0;
99
100 if (msecs_p != WAIT_INFINITE) {
101 timeval now;
102 timespec timeout, time;
103
104 gettimeofday(&now, NULL);
105 time.tv_sec = msecs_p / 1000;
106 time.tv_nsec = (msecs_p % 1000) * 1000000;
107 timeout.tv_sec = now.tv_sec + time.tv_sec;
108 timeout.tv_nsec = now.tv_usec + time.tv_nsec;
109
110 pthread_mutex_lock(&_osThread->_mut);
111 if (_osThread->_running) {
112 retcode = pthread_cond_timedwait(&_osThread->_cond, &_osThread->_mut, &timeout);
113 }
114 pthread_mutex_unlock(&_osThread->_mut);
115
116 if (retcode == ETIMEDOUT) {
117 return false;
118 } else {
119 return true;
120 }
121 } else {
122 pthread_mutex_lock(&_osThread->_mut);
123 //printf("@@@@ Thread wait (%p), running: %d\n", _osThread, _osThread->_running);
124 if (_osThread->_running) {
125 pthread_cond_wait(&_osThread->_cond, &_osThread->_mut);
126 _osThread->_running = false;
127 }
128 //printf("@@@@ Thread after wait\n");
129 pthread_mutex_unlock(&_osThread->_mut);
130 return true;
131 }
132 }
133
start()134 bool Thread::start()
135 {
136 if (running() == false) {
137 timeval now;
138 struct timezone tz;
139
140 gettimeofday(&now, &tz);
141 _startTime = now.tv_sec;
142 _osThread->_running = true;
143 if (pthread_create(&_osThread->_handle, NULL, OSThread::threadFunc, this) != 0) {
144 return false;
145 }
146 }
147
148 return true;
149 }
150
running() const151 bool Thread::running() const
152 {
153 return (_osThread->_running);
154 }
155
msleep(long msecs_p)156 void Thread::msleep(long msecs_p)
157 {
158 timespec time, rem;
159 int counter = 5; // givin it 5 tries
160
161 time.tv_sec = msecs_p / 1000;
162 time.tv_nsec = (msecs_p % 1000) * 1000000;
163 while (counter > 0) {
164 // nanosleep might return due to a signal, in which case
165 // rem will include the remaining time
166 if (nanosleep(&time, &rem) == -1) {
167 time.tv_sec = rem.tv_sec;
168 time.tv_nsec = rem.tv_nsec;
169 --counter;
170 } else {
171 break;
172 }
173 }
174 }
175
run()176 void Thread::run()
177 {
178 if (_func != NULL) {
179 _func(_param);
180 }
181 }
182
elapsedTime() const183 long Thread::elapsedTime() const
184 {
185 struct timezone tz;
186 timeval now;
187
188 gettimeofday(&now, &tz);
189 return ((now.tv_sec - _startTime)*1000);
190 }
191
192