1 |
/* |
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 *); |