File: thread.h

package info (click to toggle)
powder 117-2
  • links: PTS
  • area: non-free
  • in suites: stretch
  • size: 10,576 kB
  • ctags: 3,545
  • sloc: cpp: 55,002; makefile: 541; sh: 258; objc: 245; ansic: 107; csh: 54
file content (248 lines) | stat: -rw-r--r-- 4,625 bytes parent folder | download | duplicates (2)
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
/*
 * Licensed under CLIFE license.  See LICENCE.TXT  
 *
 * Produced by:	Jeff Lait
 *
 *      	CLIFE Development
 *
 * NAME:        thread.h ( CLIFE, C++ )
 *
 * COMMENTS:
 *	Attempt at a threading class.
 */

#ifndef __thread_h__
#define __thread_h__

typedef void *(*THREADmainFunc)(void *);

class THREAD
{
public:
    // We use this generator to return the system specific implementation.
    static THREAD	*alloc();
    static int		 numProcessors();

    // (Re)starts this, invoking the given function as the main 
    // thread program.
    virtual void	 start(THREADmainFunc func, void *data) = 0;

    // Blocks until this is done
    virtual void	 join() = 0;

    // Is this thread still processing?
    bool	 	 isActive() const { return myActive; }

    // Terminates this thread.
    virtual void	 kill() = 0;
    
protected:
			 THREAD() { myActive = false; }
    virtual 		~THREAD() {}

    void		 setActive(bool val) { myActive = val; }

    // Blocks until the thread is ready to process.
    virtual void	 waittillimready() = 0;
    virtual void	 iamdonenow() = 0;

    // Canonical main func for threads.
    static void		*wrapper(void *data);

    // No public copying.
	    THREAD(const THREAD &) { }
    THREAD &operator=(const THREAD &) { return *this; }

    bool		 myActive; 
    THREADmainFunc	 myCB;
    void		*myCBData;
};

typedef int s32;

#ifdef LINUX

#include <pthread.h>

#ifdef iPOWDER

#include <libkern/OSAtomic.h>

inline s32
testandset(s32 *addr, s32 val)
{
    // Not natively supported, sadly.
    // Too lazy to build a lock.  Yes this will bite me someday.
    int		result = *addr;
    *addr = val;
    return result;
}

inline s32
testandadd(s32 *addr, s32 val)
{
    // This does not return the original value, but that is
    // what our code expects.
    return OSAtomicAdd32(val, addr) - val;
}

#else

// Requires GCC 4.1 ++
// Consider this punishment for 4.3's behaviour with enums.
inline s32
testandset(s32 *addr, s32 val)
{
    return __sync_lock_test_and_set(addr, val);
}

inline s32
testandadd(s32 *addr, s32 val)
{
    return __sync_fetch_and_add(addr, val);
}

#endif

#else

#define _THREAD_SAFE
#define _WIN32_WINNT 0x0400
#include <windows.h>
#include <intrin.h>

#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif

#pragma intrinsic (_InterlockedExchange)
#pragma intrinsic (_InterlockedExchangeAdd)

inline s32
testandset(s32 *addr, s32 val)
{
    return (s32)_InterlockedExchange((long *)addr, (long)val);
}

inline s32
testandadd(s32 *addr, s32 val)
{
    return (s32)_InterlockedExchangeAdd((long *)addr, (long)val);
}

#endif

class ATOMIC_INT32
{
public:
    explicit ATOMIC_INT32(s32 value = 0) : myValue(value) {}

    // Swap this and val
    inline s32	exchange(s32 val)
    {
	return testandset(&myValue, val);
    }

    // Add val to this, return the old value.
    inline s32	exchangeAdd(s32 val)
    {
	return testandadd(&myValue, val);
    }

    // Add val to this, return new value.
    inline s32	add(s32 val)
    {
	return testandadd(&myValue, val) + val;
    }

    // Set self to maximum of self and val
    inline s32	maximum(s32 val)
    {
	s32	peek = exchange(val);
	while (peek > val)
	{
	    val = peek;
	    peek = exchange(val);
	}
	return peek;
    }

    void	set(s32 val) { myValue = val; }

    operator	s32() const { return myValue; }
private:
    s32		myValue;

    ATOMIC_INT32(const ATOMIC_INT32 &) {}
    ATOMIC_INT32 &operator=(const ATOMIC_INT32 &) { return *this; }
};


class LOCK
{
public:
	LOCK();
	~LOCK();

    // Non blocking attempt at the lock, returns true if now locked.
    bool	tryToLock();

    void	lock();
    void	unlock();
    bool	isLocked();

protected:
    LOCK(const LOCK &) {}
    LOCK &operator=(const LOCK &) { return *this; }

#ifdef LINUX
    pthread_mutex_t	 myLock;
    pthread_mutexattr_t	 myLockAttr;
#else
    CRITICAL_SECTION	*myLock;
#endif

    friend class CONDITION;

};

class AUTOLOCK
{
public:
    AUTOLOCK(LOCK &lock) : myLock(lock) { myLock.lock(); }
    ~AUTOLOCK() { myLock.unlock(); }

protected:
    LOCK	&myLock;
};

class CONDITION
{
public:
    CONDITION();
    ~CONDITION();

    // Lock is currently set.  We will unlock it, block, then
    // when condition is triggered relock it and return.
    void	wait(LOCK &lock);

    // Trigger, allowing one thread through.
    // Caller should currently have the wait lock.
    void	trigger();
private:

    CONDITION(const CONDITION &) {}
    CONDITION &operator=(const CONDITION &) { return *this; }

#ifdef LINUX
    pthread_cond_t	myCond;
#else
    ATOMIC_INT32	myNumWaiting;
    HANDLE		myEvent;
#endif
};

#endif