aboutsummaryrefslogtreecommitdiff
path: root/odb/details/win32/thread.cxx
blob: 46720d4a05af65a85975222e95d316e3b99ea5f6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// file      : odb/details/win32/thread.cxx
// license   : GNU GPL v2; see accompanying LICENSE file

#include <odb/details/win32/windows.hxx>
#include <process.h> // _beginthreadex, _endthreadex

#include <odb/details/unique-ptr.hxx>
#include <odb/details/win32/thread.hxx>
#include <odb/details/win32/exceptions.hxx>

unsigned int __stdcall
odb_thread_thunk (void* arg)
{
  odb::details::thread::thread_thunk (arg);
  _endthreadex (0);
  return 0;
}

namespace odb
{
  namespace details
  {
    void thread::
    thread_thunk (void* arg)
    {
      data* d (static_cast<data*> (arg));
      d->ret = d->func (d->arg);
      d->mutex.lock ();
      unsigned char count = --d->count;
      d->mutex.unlock ();

      if (count == 0)
        delete d;
    }

    thread::
    ~thread ()
    {
      if (handle_ != 0)
      {
        CloseHandle (handle_);

        // Win32 mutex implementation does not throw.
        //
        data_->mutex.lock ();
        unsigned char count = --data_->count;
        data_->mutex.unlock ();

        if (count == 0)
          delete data_;
      }
    }

    thread::
    thread (void* (*func) (void*), void* arg)
    {
      unique_ptr<data> d (new data);
      d->func = func;
      d->arg = arg;
      d->count = 2; // One for the thread and one for us.

      handle_ = (HANDLE)_beginthreadex (
        0, 0, &odb_thread_thunk, d.get (), 0, 0);

      if (handle_ == 0)
        throw win32_exception ();

      data_ = d.release ();
    }

    void* thread::
    join ()
    {
      void* r;

      if (WaitForSingleObject (handle_, INFINITE) != 0)
        throw win32_exception ();

      r = data_->ret;

      CloseHandle (handle_);
      delete data_;
      handle_ = 0;
      data_ = 0;
       return r;
    }
  }
}