1 |
gpertea |
107 |
/* |
2 |
|
|
* cpp-ification of yarn.h -- generic interface for thread operations |
3 |
|
|
* Copyright (C) 2008 Mark Adler |
4 |
|
|
* Version 1.1 26 Oct 2008 Mark Adler |
5 |
|
|
*/ |
6 |
|
|
|
7 |
|
|
/* |
8 |
|
|
This software is provided 'as-is', without any express or implied |
9 |
|
|
warranty. In no event will the author be held liable for any damages |
10 |
|
|
arising from the use of this software. |
11 |
|
|
|
12 |
|
|
Permission is granted to anyone to use this software for any purpose, |
13 |
|
|
including commercial applications, and to alter it and redistribute it |
14 |
|
|
freely, subject to the following restrictions: |
15 |
|
|
|
16 |
|
|
1. The origin of this software must not be misrepresented; you must not |
17 |
|
|
claim that you wrote the original software. If you use this software |
18 |
|
|
in a product, an acknowledgment in the product documentation would be |
19 |
|
|
appreciated but is not required. |
20 |
|
|
2. Altered source versions must be plainly marked as such, and must not be |
21 |
|
|
misrepresented as being the original software. |
22 |
|
|
3. This notice may not be removed or altered from any source distribution. |
23 |
|
|
|
24 |
|
|
Mark Adler |
25 |
|
|
madler@alumni.caltech.edu |
26 |
|
|
*/ |
27 |
|
|
|
28 |
|
|
/* Basic thread operations |
29 |
|
|
|
30 |
|
|
This interface isolates the local operating system implementation of threads |
31 |
|
|
from the application in order to facilitate platform independent use of |
32 |
|
|
threads. All of the implementation details are deliberately hidden. |
33 |
|
|
|
34 |
|
|
Assuming adequate system resources and proper use, none of these functions |
35 |
|
|
can fail. As a result, any errors encountered will cause an exit() to be |
36 |
|
|
executed. |
37 |
|
|
|
38 |
|
|
These functions allow the simple launching and joining of threads, and the |
39 |
|
|
locking of objects and synchronization of changes of objects. The latter is |
40 |
|
|
implemented with a single lock type that contains an integer value. The |
41 |
|
|
value can be ignored for simple exclusive access to an object, or the value |
42 |
|
|
can be used to signal and wait for changes to an object. |
43 |
|
|
|
44 |
|
|
-- Arguments -- |
45 |
|
|
|
46 |
|
|
thread *thread; identifier for launched thread, used by join |
47 |
|
|
void probe(void *); pointer to function "probe", run when thread starts |
48 |
|
|
void *payload; single argument passed to the probe function |
49 |
|
|
lock *lock; a lock with a value -- used for exclusive access to |
50 |
|
|
an object and to synchronize threads waiting for |
51 |
|
|
changes to an object |
52 |
|
|
long val; value to set lock, increment lock, or wait for |
53 |
|
|
int n; number of threads joined |
54 |
|
|
|
55 |
|
|
-- Thread functions -- |
56 |
|
|
|
57 |
|
|
thread = launch(probe, payload) - launch a thread -- exit via probe() return |
58 |
|
|
join(thread) - join a thread and by joining end it, waiting for the thread |
59 |
|
|
to exit if it hasn't already -- will free the resources allocated by |
60 |
|
|
launch() (don't try to join the same thread more than once) |
61 |
|
|
n = join_all() - join all threads launched by launch() that are not joined |
62 |
|
|
yet and free the resources allocated by the launches, usually to clean |
63 |
|
|
up when the thread processing is done -- join_all() returns an int with |
64 |
|
|
the count of the number of threads joined (join_all() should only be |
65 |
|
|
called from the main thread, and should only be called after any calls |
66 |
|
|
of join() have completed) |
67 |
|
|
destruct(thread) - terminate the thread in mid-execution and join it |
68 |
|
|
(depending on the implementation, the termination may not be immediate, |
69 |
|
|
but may wait for the thread to execute certain thread or file i/o |
70 |
|
|
operations) |
71 |
|
|
|
72 |
|
|
-- Lock functions -- |
73 |
|
|
|
74 |
|
|
lock = new_lock(val) - create a new lock with initial value val (lock is |
75 |
|
|
created in the released state) |
76 |
|
|
possess(lock) - acquire exclusive possession of a lock, waiting if necessary |
77 |
|
|
twist(lock, [TO | BY], val) - set lock to or increment lock by val, signal |
78 |
|
|
all threads waiting on this lock and then release the lock -- must |
79 |
|
|
possess the lock before calling (twist releases, so don't do a |
80 |
|
|
release() after a twist() on the same lock) |
81 |
|
|
wait_for(lock, [TO_BE | NOT_TO_BE | TO_BE_MORE_THAN | TO_BE_LESS_THAN], val) |
82 |
|
|
- wait on lock value to be, not to be, be greater than, or be less than |
83 |
|
|
val -- must possess the lock before calling, will possess the lock on |
84 |
|
|
return but the lock is released while waiting to permit other threads |
85 |
|
|
to use twist() to change the value and signal the change (so make sure |
86 |
|
|
that the object is in a usable state when waiting) |
87 |
|
|
release(lock) - release a possessed lock (do not try to release a lock that |
88 |
|
|
the current thread does not possess) |
89 |
|
|
val = peek_lock(lock) - return the value of the lock (assumes that lock is |
90 |
|
|
already possessed, no possess or release is done by peek_lock()) |
91 |
|
|
free_lock(lock) - free the resources allocated by new_lock() (application |
92 |
|
|
must assure that the lock is released before calling free_lock()) |
93 |
|
|
|
94 |
|
|
-- Memory allocation --- |
95 |
|
|
|
96 |
|
|
yarn_mem(better_malloc, better_free) - set the memory allocation and free |
97 |
|
|
routines for use by the yarn routines where the supplied routines have |
98 |
|
|
the same interface and operation as malloc() and free(), and may be |
99 |
|
|
provided in order to supply thread-safe memory allocation routines or |
100 |
|
|
for any other reason -- by default malloc() and free() will be used |
101 |
|
|
|
102 |
|
|
-- Error control -- |
103 |
|
|
|
104 |
|
|
yarn_name - a char pointer to a string that will be the prefix for any error |
105 |
|
|
messages that these routines generate before exiting -- if not changed |
106 |
|
|
by the application, "yarn" will be used |
107 |
|
|
yarn_abort - an external function that will be executed when there is an |
108 |
|
|
internal yarn error, due to out of memory or misuse -- this function |
109 |
|
|
may exit to abort the application, or if it returns, the yarn error |
110 |
|
|
handler will exit (set to NULL by default for no action) |
111 |
|
|
*/ |
112 |
|
|
|
113 |
|
|
extern char *yarn_prefix; |
114 |
|
|
extern void (*yarn_abort)(int); |
115 |
|
|
typedef struct thread_s thread; |
116 |
|
|
typedef struct lock_s lock; |
117 |
|
|
|
118 |
|
|
class GYarn { |
119 |
|
|
public: |
120 |
|
|
//void yarn_mem(void *(*)(size_t), void (*)(void *)); |
121 |
|
|
void mem(void *(*)(size_t), void (*)(void *)); |
122 |
|
|
thread *launch(void (*)(void *), void *); |
123 |
|
|
void join(thread *); |
124 |
|
|
int join_all(void); |
125 |
|
|
void destruct(thread *); |
126 |
|
|
|
127 |
|
|
}; |
128 |
|
|
|
129 |
|
|
|
130 |
|
|
|
131 |
|
|
|
132 |
|
|
lock *new_lock(long); |
133 |
|
|
void possess(lock *); |
134 |
|
|
void release(lock *); |
135 |
|
|
enum twist_op { TO, BY }; |
136 |
|
|
void twist(lock *, enum twist_op, long); |
137 |
|
|
enum wait_op { |
138 |
|
|
TO_BE, /* or */ NOT_TO_BE, /* that is the question */ |
139 |
|
|
TO_BE_MORE_THAN, TO_BE_LESS_THAN }; |
140 |
|
|
void wait_for(lock *, enum wait_op, long); |
141 |
|
|
long peek_lock(lock *); |
142 |
|
|
void free_lock(lock *); |