1 /*
2  *
3  *  C++ Portable Types Library (PTypes)
4  *  Version 2.1.1  Released 27-Jun-2007
5  *
6  *  Copyright (C) 2001-2007 Hovik Melikyan
7  *
8  *  http://www.melikyan.com/ptypes/
9  *
10  */
11 
12 #ifdef WIN32
13 #  include <process.h>
14 #else
15 #  include <pthread.h>
16 #endif
17 
18 #include "pasync.h"
19 
20 
21 PTYPES_BEGIN
22 
23 
thread(bool iautofree)24 thread::thread(bool iautofree)
25     :
26 #ifdef WIN32
27     id(0),
28 #endif
29     handle(0), autofree(iautofree),
30     running(0), signaled(0), finished(0), freed(0),
31     reserved(0), relaxsem(0)
32 {
33 }
34 
35 
~thread()36 thread::~thread()
37 {
38     if (pexchange(&freed, 1) != 0)
39         return;
40 #ifdef WIN32
41     if (autofree)
42         // MSDN states this is not necessary, however, without closing
43         // the handle debuggers show an obvious handle leak here
44         CloseHandle(handle);
45 #else
46     // though we require non-autofree threads to always call waitfor(),
47     // the statement below is provided to cleanup thread resources even
48     // if waitfor() was not called.
49     if (!autofree && running)
50         pthread_detach(handle);
51 #endif
52 }
53 
54 
signal()55 void thread::signal()
56 {
57     if (pexchange(&signaled, 1) == 0)
58         relaxsem.post();
59 }
60 
61 
waitfor()62 void thread::waitfor()
63 {
64     if (pexchange(&freed, 1) != 0)
65         return;
66     if (pthrequal(get_id()))
67         fatal(CRIT_FIRST + 47, "Can not waitfor() on myself");
68     if (autofree)
69         fatal(CRIT_FIRST + 48, "Can not waitfor() on an autofree thread");
70 #ifdef WIN32
71     WaitForSingleObject(handle, INFINITE);
72     CloseHandle(handle);
73 #else
74     pthread_join(handle, nil);
75 //  detaching after 'join' is not required (or even do harm on some systems)
76 //  except for HPUX. we don't support HPUX yet.
77 //    pthread_detach(handle);
78 #endif
79     handle = 0;
80 }
81 
82 
83 #ifdef WIN32
_threadproc(void * arg)84 unsigned _stdcall _threadproc(void* arg)
85 {
86 #else
87 void* _threadproc(void* arg)
88 {
89 #endif
90     thread* thr = (thread*)arg;
91 #ifndef WIN32
92     if (thr->autofree)
93         // start() does not assign the handle for autofree threads
94         thr->handle = pthread_self();
95 #endif
96     try
97     {
98         thr->execute();
99     }
100     catch(exception*)
101     {
102         _threadepilog(thr);
103         throw;
104     }
105     _threadepilog(thr);
106     return 0;
107 }
108 
109 
110 void _threadepilog(thread* thr)
111 {
112     try
113     {
114         thr->cleanup();
115     }
116     catch(exception* e)
117     {
118         delete e;
119     }
120     pexchange(&thr->finished, 1);
121     if (thr->autofree)
122         delete thr;
123 }
124 
125 
126 void thread::start()
127 {
128     if (pexchange(&running, 1) == 0)
129     {
130 #ifdef WIN32
131         handle = (HANDLE)_beginthreadex(nil, 0, _threadproc, this, 0, &id);
132         if (handle == 0)
133             fatal(CRIT_FIRST + 40, "CreateThread() failed");
134 #else
135         pthread_t temp_handle;
136         pthread_attr_t attr;
137         pthread_attr_init(&attr);
138         pthread_attr_setdetachstate(&attr,
139             autofree ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE);
140         if (pthread_create(autofree ? &temp_handle : &handle,
141                 &attr, _threadproc, this) != 0)
142             fatal(CRIT_FIRST + 40, "pthread_create() failed");
143         pthread_attr_destroy(&attr);
144 #endif
145     }
146 }
147 
148 
149 void thread::cleanup()
150 {
151 }
152 
153 
154 PTYPES_END
155