The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
thread.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2016 by David White <[email protected]>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #include "global.hpp"
16 
17 #include <vector>
18 
19 #include "log.hpp"
20 #include "thread.hpp"
21 
22 #include <SDL_mutex.h>
23 #include <SDL_thread.h>
24 #include <SDL_version.h>
25 
26 #define ERR_G LOG_STREAM(err, lg::general())
27 
28 boost::uint32_t threading::thread::get_id() { return SDL_GetThreadID(thread_); }
29 
31 
32 static int run_async_operation(void* data)
33 {
34  threading::async_operation_ptr op(*reinterpret_cast<threading::async_operation_ptr*>(data));
35  op->run();
36 
37  const threading::lock l(op->get_mutex());
38  op->notify_finished(); //in case the operation didn't notify of finishing
39 
40  return 0;
41 }
42 
43 namespace {
44 
45 std::vector<SDL_Thread*> detached_threads;
46 
47 }
48 
49 namespace threading {
50 
52 {
53  for(std::vector<SDL_Thread*>::iterator i = detached_threads.begin(); i != detached_threads.end(); ++i) {
54  SDL_WaitThread(*i,nullptr);
55  }
56 }
57 
58 thread::thread(int (*f)(void*), void* data)
59  : thread_(SDL_CreateThread(f, "", data))
60 {
61 }
62 
64 {
65  join();
66 }
67 
69 {
70  if(thread_ != nullptr) {
71  SDL_WaitThread(thread_,nullptr);
72  thread_ = nullptr;
73  }
74 }
75 
77 {
78  detached_threads.push_back(thread_);
79  thread_ = nullptr;
80 }
81 
82 mutex::mutex() : m_(SDL_CreateMutex())
83 {}
84 
86 {
87  SDL_DestroyMutex(m_);
88 }
89 
90 lock::lock(mutex& m) : m_(m)
91 {
92  SDL_mutexP(m_.m_);
93 }
94 
96 {
97  SDL_mutexV(m_.m_);
98 }
99 
100 condition::condition() : cond_(SDL_CreateCond())
101 {}
102 
104 {
105  SDL_DestroyCond(cond_);
106 }
107 
108 bool condition::wait(const mutex& m)
109 {
110  return SDL_CondWait(cond_,m.m_) == 0;
111 }
112 
114 {
115  const int res = SDL_CondWaitTimeout(cond_,m.m_,timeout);
116  switch(res) {
117  case 0: return WAIT_OK;
118  case SDL_MUTEX_TIMEDOUT: return WAIT_TIMED_OUT;
119  default:
120  ERR_G << "SDL_CondWaitTimeout: " << SDL_GetError() << std::endl;
121  return WAIT_ERROR;
122  }
123 }
124 
126 {
127  if(SDL_CondSignal(cond_) < 0) {
128  ERR_G << "SDL_CondSignal: " << SDL_GetError() << std::endl;
129  return false;
130  }
131 
132  return true;
133 }
134 
136 {
137  if(SDL_CondBroadcast(cond_) < 0) {
138  ERR_G << "SDL_CondBroadcast: " << SDL_GetError() << std::endl;
139  return false;
140  }
141  return true;
142 }
143 
145 {
146  finishedVar_ = true;
147  return finished_.notify_one();
148 }
150 
152 {
153  //the thread must be created after the lock, and also destroyed after it.
154  //this is because during the thread's execution, we must always hold the mutex
155  //unless we are waiting on notification that the thread is finished, or we have
156  //already received that notification.
157  //
158  //we cannot hold the mutex while waiting for the thread to join though, because
159  //the thread needs access to the mutex before it terminates
160  {
161  const lock l(get_mutex());
162  active_.push_back(this_ptr);
163  thread_.reset(new thread(run_async_operation,&this_ptr));
164 
165  bool completed = false;
166  while(wait.process() == waiter::WAIT) {
168  if(res == condition::WAIT_OK || finishedVar_) {
169  completed = true;
170  break;
171  } else if(res == condition::WAIT_ERROR) {
172  break;
173  }
174  }
175 
176  if(!completed) {
177  aborted_ = true;
178  return ABORTED;
179  }
180  }
181 
182  return COMPLETED;
183 }
184 
185 
186 }
thread(int(*f)(void *), void *data=nullptr)
Definition: thread.cpp:58
SDL_Thread * thread_
Definition: thread.hpp:85
boost::uint32_t uint32_t
Definition: xbrz.hpp:45
boost::scoped_ptr< thread > thread_
Definition: thread.hpp:247
RESULT execute(async_operation_ptr this_ptr, waiter &wait)
Definition: thread.cpp:151
GLint GLenum GLsizei GLint GLsizei const GLvoid * data
Definition: glew.h:1347
GLdouble l
Definition: glew.h:6966
WAIT_TIMEOUT_RESULT wait_timeout(const mutex &m, unsigned int timeout)
Definition: thread.cpp:113
static active_operation_list active_
Definition: thread.hpp:253
SDL_mutex *const m_
Definition: thread.hpp:107
SDL_cond *const cond_
Definition: thread.hpp:190
#define ERR_G
Definition: thread.cpp:26
virtual ACTION process()=0
static int run_async_operation(void *data)
Definition: thread.cpp:32
GLuint res
Definition: glew.h:9258
GLbitfield GLuint64 timeout
Definition: glew.h:4717
lock(mutex &m)
Definition: thread.cpp:90
mutex & m_
Definition: thread.hpp:132
size_t i
Definition: function.cpp:1057
boost::uint32_t get_current_thread_id()
Definition: thread.cpp:30
const GLdouble * m
Definition: glew.h:6968
boost::uint32_t get_id()
Definition: thread.cpp:28
Standard logging facilities (interface).
std::list< async_operation_ptr > active_operation_list
Definition: thread.hpp:206
std::string::const_iterator iterator
Definition: tokenizer.hpp:21
bool wait(const mutex &m)
Definition: thread.cpp:108
GLclampf f
Definition: glew.h:3024