win32/mt_threadimpl.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) Sergey P. Derevyago, 2008.
00003  *
00004  * Permission to copy, use, modify, sell and distribute this software is granted
00005  * provided this copyright notice appears in all copies.
00006  * This software is provided "as is" without express or implied warranty, and
00007  * with no claim as to its suitability for any purpose.
00008  *
00009  */
00010 
00016 #include <windows.h>
00017 #include <process.h>
00018 #include <ders/thread.hpp>
00019 #include <algorithm>
00020 #include <vector>
00021 #include <ders/error.hpp>
00022 
00023 namespace {
00024 
00025 using namespace std;
00026 using namespace ders;
00027 using namespace ders::detail;
00028 
00029 struct win_thread : public thread {
00030        mem_pool& mp;
00031        tc_ptr core;
00032 
00033        win_thread(mem_pool& m, void (*strt)(void*), void* arg);
00034        ~win_thread();
00035 
00036        virtual bool is_running();
00037        virtual void join();
00038        virtual void destroy(mem_pool& mp2) { destroy_this(this, mp2); }
00039 
00040        void start();
00041 };
00042 
00043 struct win_mutex : public mutex {
00044        CRITICAL_SECTION cs;
00045 
00046        win_mutex();
00047        ~win_mutex();
00048 
00049        virtual void lock();
00050        virtual void unlock();
00051 
00052        virtual void destroy(mem_pool& mp2) { destroy_this(this, mp2); }
00053 };
00054 
00055 class event_cache {
00056       vector<HANDLE> evs;
00057 
00058       event_cache(const event_cache&);
00059       event_cache& operator=(const event_cache&);
00060 
00061  public:
00062       event_cache();
00063       ~event_cache();
00064 
00065       HANDLE getEvent();
00066       void returnEvent(HANDLE ev);
00067 };
00068 
00069 struct win_cond_var : public cond_var {
00070        mutex& m;
00071        event_cache evc;
00072        vector<HANDLE> wts;
00073 
00074        win_cond_var(mutex& mtx);
00075        ~win_cond_var();
00076 
00077        virtual void wait(long timeout);
00078        virtual void notify();
00079        virtual void notify_all();
00080 
00081        virtual void destroy(mem_pool& mp2) { destroy_this(this, mp2); }
00082 };
00083 
00084 unsigned __stdcall win32_start(void* arg)
00085 {
00086  static_cast<thr_core*>(arg)->start();
00087  return 0;
00088 }
00089 
00090 win_thread::win_thread(mem_pool& m, void (*strt)(void*), void* arg) :
00091   mp(m), core(true, new thr_core(strt, arg))
00092 {
00093 }
00094 
00095 win_thread::~win_thread()
00096 {
00097 }
00098 
00099 bool win_thread::is_running()
00100 {
00101  return core->is_running();
00102 }
00103 
00104 void win_thread::join()
00105 {
00106  core->join();
00107 }
00108 
00109 void win_thread::start()
00110 {
00111  unsigned tid;
00112  HANDLE thn=(HANDLE)_beginthreadex(0, 0, win32_start, core.ptr, 0, &tid);
00113  if (thn==0) {
00114     core->clear_rng();
00115 
00116     throw newErrorException(mp, _FLINE_, "Can't begin thread", convert_errno(
00117       errno));
00118  }
00119 
00120  CloseHandle(thn);
00121 }
00122 
00123 win_mutex::win_mutex()
00124 {
00125  InitializeCriticalSection(&cs);
00126 }
00127 
00128 win_mutex::~win_mutex()
00129 {
00130  DeleteCriticalSection(&cs);
00131 }
00132 
00133 void win_mutex::lock()
00134 {
00135  EnterCriticalSection(&cs);
00136 }
00137 
00138 void win_mutex::unlock()
00139 {
00140  LeaveCriticalSection(&cs);
00141 }
00142 
00143 event_cache::event_cache()
00144 {
00145  evs.reserve(16);
00146 }
00147 
00148 event_cache::~event_cache()
00149 {
00150  for (int i=0, end=evs.size(); i<end; i++) CloseHandle(evs[i]);
00151 }
00152 
00153 HANDLE event_cache::getEvent()
00154 {
00155  HANDLE ev;
00156  if (evs.size()>0) {
00157     ev=evs.back();
00158     evs.pop_back();
00159  }
00160  else {
00161       ev=CreateEvent(0, FALSE, FALSE, 0);
00162       hard_assert(ev!=0);
00163  }
00164 
00165  return ev;
00166 }
00167 
00168 void event_cache::returnEvent(HANDLE ev)
00169 {
00170  assert(ev!=0);
00171  try { evs.push_back(ev); }
00172  catch (...) {
00173        CloseHandle(ev);
00174        throw;
00175  }
00176 }
00177 
00178 win_cond_var::win_cond_var(mutex& mtx) : m(mtx)
00179 {
00180  wts.reserve(16);
00181 }
00182 
00183 win_cond_var::~win_cond_var()
00184 {
00185  assert(wts.size()==0);
00186 }
00187 
00188 void win_cond_var::wait(long timeout)
00189 {
00190  HANDLE ev=evc.getEvent();
00191  try { wts.push_back(ev); }
00192  catch (...) {
00193        CloseHandle(ev);
00194        throw;
00195  }
00196 
00197  m.unlock();
00198 
00199  DWORD rcd=WaitForSingleObject(ev, (timeout==infinite) ? timeout : INFINITE);
00200  hard_assert(rcd==WAIT_OBJECT_0 || rcd==WAIT_TIMEOUT);
00201 
00202  m.lock();
00203 
00204  if (rcd==WAIT_TIMEOUT) {
00205     vector<HANDLE>::iterator it=find(wts.begin(), wts.end(), ev);
00206     if (it==wts.end()) {
00207        BOOL rc=ResetEvent(ev);
00208        hard_assert(rc!=0);
00209     }
00210     else wts.erase(it);
00211  }
00212 
00213  evc.returnEvent(ev);
00214 }
00215 
00216 void win_cond_var::notify()
00217 {
00218  if (wts.size()==0) return;
00219 
00220  HANDLE ev=wts.back();
00221  wts.pop_back();
00222 
00223  BOOL rc=SetEvent(ev);
00224  hard_assert(rc!=0);
00225 }
00226 
00227 void win_cond_var::notify_all()
00228 {
00229  if (wts.size()==0) return;
00230 
00231  for (int i=0, end=wts.size(); i<end; i++) {
00232      BOOL rc=SetEvent(wts[i]);
00233      hard_assert(rc!=0);
00234  }
00235 
00236  wts.clear();
00237 }
00238 
00239 }  // unnamed
00240 
00241 namespace ders {  // ::ders
00242 
00243 sh_thread new_thread(mem_pool& mp, void (*start)(void*), void* arg)
00244 {
00245  mp_newbuf<win_thread> buf(mp);
00246  sh_thread ret(buf.pool(), buf.rls(::new(buf.get()) win_thread(buf.pool(),
00247    start, arg)));
00248 
00249  static_cast<win_thread*>(ret.get())->start();
00250 
00251  return ret;
00252 }
00253 
00254 sh_mutex new_mutex(mem_pool& mp)
00255 {
00256  mp_newbuf<win_mutex> buf(mp);
00257  return sh_mutex(buf.pool(), buf.rls(::new(buf.get()) win_mutex));
00258 }
00259 
00260 sh_cond_var new_cond_var(mem_pool& mp, mutex& mtx)
00261 {
00262  mp_newbuf<win_cond_var> buf(mp);
00263  return sh_cond_var(buf.pool(), buf.rls(::new(buf.get()) win_cond_var(mtx)));
00264 }
00265 
00266 }  // namespace ::ders
00267 

Generated on Tue Dec 8 11:35:32 2009 for derslib by  doxygen 1.5.5