|
1 |
|
2 /* GNU pth threads interface |
|
3 http://www.gnu.org/software/pth |
|
4 2000-05-03 Andy Dustman <andy@dustman.net> |
|
5 |
|
6 Adapted from Posix threads interface |
|
7 12 May 1997 -- david arnold <davida@pobox.com> |
|
8 */ |
|
9 |
|
10 #include <stdlib.h> |
|
11 #include <string.h> |
|
12 #include <pth.h> |
|
13 |
|
14 /* A pth mutex isn't sufficient to model the Python lock type |
|
15 * because pth mutexes can be acquired multiple times by the |
|
16 * same thread. |
|
17 * |
|
18 * The pth_lock struct implements a Python lock as a "locked?" bit |
|
19 * and a <condition, mutex> pair. In general, if the bit can be acquired |
|
20 * instantly, it is, else the pair is used to block the thread until the |
|
21 * bit is cleared. |
|
22 */ |
|
23 |
|
24 typedef struct { |
|
25 char locked; /* 0=unlocked, 1=locked */ |
|
26 /* a <cond, mutex> pair to handle an acquire of a locked lock */ |
|
27 pth_cond_t lock_released; |
|
28 pth_mutex_t mut; |
|
29 } pth_lock; |
|
30 |
|
31 #define CHECK_STATUS(name) if (status == -1) { printf("%d ", status); perror(name); error = 1; } |
|
32 |
|
33 pth_attr_t PyThread_attr; |
|
34 |
|
35 /* |
|
36 * Initialization. |
|
37 */ |
|
38 |
|
39 static void PyThread__init_thread(void) |
|
40 { |
|
41 pth_init(); |
|
42 PyThread_attr = pth_attr_new(); |
|
43 pth_attr_set(PyThread_attr, PTH_ATTR_STACK_SIZE, 1<<18); |
|
44 pth_attr_set(PyThread_attr, PTH_ATTR_JOINABLE, FALSE); |
|
45 } |
|
46 |
|
47 /* |
|
48 * Thread support. |
|
49 */ |
|
50 |
|
51 |
|
52 long PyThread_start_new_thread(void (*func)(void *), void *arg) |
|
53 { |
|
54 pth_t th; |
|
55 dprintf(("PyThread_start_new_thread called\n")); |
|
56 if (!initialized) |
|
57 PyThread_init_thread(); |
|
58 |
|
59 th = pth_spawn(PyThread_attr, |
|
60 (void* (*)(void *))func, |
|
61 (void *)arg |
|
62 ); |
|
63 |
|
64 return th; |
|
65 } |
|
66 |
|
67 long PyThread_get_thread_ident(void) |
|
68 { |
|
69 volatile pth_t threadid; |
|
70 if (!initialized) |
|
71 PyThread_init_thread(); |
|
72 /* Jump through some hoops for Alpha OSF/1 */ |
|
73 threadid = pth_self(); |
|
74 return (long) *(long *) &threadid; |
|
75 } |
|
76 |
|
77 static void do_PyThread_exit_thread(int no_cleanup) |
|
78 { |
|
79 dprintf(("PyThread_exit_thread called\n")); |
|
80 if (!initialized) { |
|
81 if (no_cleanup) |
|
82 _exit(0); |
|
83 else |
|
84 exit(0); |
|
85 } |
|
86 } |
|
87 |
|
88 void PyThread_exit_thread(void) |
|
89 { |
|
90 do_PyThread_exit_thread(0); |
|
91 } |
|
92 |
|
93 void PyThread__exit_thread(void) |
|
94 { |
|
95 do_PyThread_exit_thread(1); |
|
96 } |
|
97 |
|
98 #ifndef NO_EXIT_PROG |
|
99 static void do_PyThread_exit_prog(int status, int no_cleanup) |
|
100 { |
|
101 dprintf(("PyThread_exit_prog(%d) called\n", status)); |
|
102 if (!initialized) |
|
103 if (no_cleanup) |
|
104 _exit(status); |
|
105 else |
|
106 exit(status); |
|
107 } |
|
108 |
|
109 void PyThread_exit_prog(int status) |
|
110 { |
|
111 do_PyThread_exit_prog(status, 0); |
|
112 } |
|
113 |
|
114 void PyThread__exit_prog(int status) |
|
115 { |
|
116 do_PyThread_exit_prog(status, 1); |
|
117 } |
|
118 #endif /* NO_EXIT_PROG */ |
|
119 |
|
120 /* |
|
121 * Lock support. |
|
122 */ |
|
123 PyThread_type_lock PyThread_allocate_lock(void) |
|
124 { |
|
125 pth_lock *lock; |
|
126 int status, error = 0; |
|
127 |
|
128 dprintf(("PyThread_allocate_lock called\n")); |
|
129 if (!initialized) |
|
130 PyThread_init_thread(); |
|
131 |
|
132 lock = (pth_lock *) malloc(sizeof(pth_lock)); |
|
133 memset((void *)lock, '\0', sizeof(pth_lock)); |
|
134 if (lock) { |
|
135 lock->locked = 0; |
|
136 status = pth_mutex_init(&lock->mut); |
|
137 CHECK_STATUS("pth_mutex_init"); |
|
138 status = pth_cond_init(&lock->lock_released); |
|
139 CHECK_STATUS("pth_cond_init"); |
|
140 if (error) { |
|
141 free((void *)lock); |
|
142 lock = NULL; |
|
143 } |
|
144 } |
|
145 dprintf(("PyThread_allocate_lock() -> %p\n", lock)); |
|
146 return (PyThread_type_lock) lock; |
|
147 } |
|
148 |
|
149 void PyThread_free_lock(PyThread_type_lock lock) |
|
150 { |
|
151 pth_lock *thelock = (pth_lock *)lock; |
|
152 |
|
153 dprintf(("PyThread_free_lock(%p) called\n", lock)); |
|
154 |
|
155 free((void *)thelock); |
|
156 } |
|
157 |
|
158 int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) |
|
159 { |
|
160 int success; |
|
161 pth_lock *thelock = (pth_lock *)lock; |
|
162 int status, error = 0; |
|
163 |
|
164 dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); |
|
165 |
|
166 status = pth_mutex_acquire(&thelock->mut, !waitflag, NULL); |
|
167 CHECK_STATUS("pth_mutex_acquire[1]"); |
|
168 success = thelock->locked == 0; |
|
169 if (success) thelock->locked = 1; |
|
170 status = pth_mutex_release( &thelock->mut ); |
|
171 CHECK_STATUS("pth_mutex_release[1]"); |
|
172 |
|
173 if ( !success && waitflag ) { |
|
174 /* continue trying until we get the lock */ |
|
175 |
|
176 /* mut must be locked by me -- part of the condition |
|
177 * protocol */ |
|
178 status = pth_mutex_acquire( &thelock->mut, !waitflag, NULL ); |
|
179 CHECK_STATUS("pth_mutex_acquire[2]"); |
|
180 while ( thelock->locked ) { |
|
181 status = pth_cond_await(&thelock->lock_released, |
|
182 &thelock->mut, NULL); |
|
183 CHECK_STATUS("pth_cond_await"); |
|
184 } |
|
185 thelock->locked = 1; |
|
186 status = pth_mutex_release( &thelock->mut ); |
|
187 CHECK_STATUS("pth_mutex_release[2]"); |
|
188 success = 1; |
|
189 } |
|
190 if (error) success = 0; |
|
191 dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); |
|
192 return success; |
|
193 } |
|
194 |
|
195 void PyThread_release_lock(PyThread_type_lock lock) |
|
196 { |
|
197 pth_lock *thelock = (pth_lock *)lock; |
|
198 int status, error = 0; |
|
199 |
|
200 dprintf(("PyThread_release_lock(%p) called\n", lock)); |
|
201 |
|
202 status = pth_mutex_acquire( &thelock->mut, 0, NULL ); |
|
203 CHECK_STATUS("pth_mutex_acquire[3]"); |
|
204 |
|
205 thelock->locked = 0; |
|
206 |
|
207 status = pth_mutex_release( &thelock->mut ); |
|
208 CHECK_STATUS("pth_mutex_release[3]"); |
|
209 |
|
210 /* wake up someone (anyone, if any) waiting on the lock */ |
|
211 status = pth_cond_notify( &thelock->lock_released, 0 ); |
|
212 CHECK_STATUS("pth_cond_notify"); |
|
213 } |