thread_pth.h 7.06 KB
Newer Older
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

/* GNU pth threads interface
   http://www.gnu.org/software/pth
   2000-05-03 Andy Dustman <andy@dustman.net>

   Adapted from Posix threads interface 
   12 May 1997 -- david arnold <davida@pobox.com>
 */

#include <stdlib.h>
#include <string.h>
#include <pth.h>

/* A pth mutex isn't sufficient to model the Python lock type
 * because pth mutexes can be acquired multiple times by the
 * same thread.
 *
 * The pth_lock struct implements a Python lock as a "locked?" bit
 * and a <condition, mutex> pair.  In general, if the bit can be acquired
 * instantly, it is, else the pair is used to block the thread until the
 * bit is cleared.
 */

typedef struct {
	char             locked; /* 0=unlocked, 1=locked */
	/* a <cond, mutex> pair to handle an acquire of a locked lock */
	pth_cond_t   lock_released;
	pth_mutex_t  mut;
} pth_lock;

#define CHECK_STATUS(name)  if (status == -1) { printf("%d ", status); perror(name); error = 1; }

/*
 * Initialization.
 */

37
static void PyThread__init_thread(void)
38 39 40 41 42 43 44 45 46
{
	pth_init();
}

/*
 * Thread support.
 */


47
long PyThread_start_new_thread(void (*func)(void *), void *arg)
48 49 50 51 52 53 54
{
	pth_t th;
	dprintf(("PyThread_start_new_thread called\n"));
	if (!initialized)
		PyThread_init_thread();

	th = pth_spawn(PTH_ATTR_DEFAULT,
55
				 (void* (*)(void *))func,
56 57 58
				 (void *)arg
				 );

59
	return th;
60 61
}

62
long PyThread_get_thread_ident(void)
63 64 65 66 67 68 69 70 71
{
	volatile pth_t threadid;
	if (!initialized)
		PyThread_init_thread();
	/* Jump through some hoops for Alpha OSF/1 */
	threadid = pth_self();
	return (long) *(long *) &threadid;
}

72
static void do_PyThread_exit_thread(int no_cleanup)
73 74 75 76 77 78 79 80 81 82
{
	dprintf(("PyThread_exit_thread called\n"));
	if (!initialized) {
		if (no_cleanup)
			_exit(0);
		else
			exit(0);
	}
}

83
void PyThread_exit_thread(void)
84 85 86 87
{
	do_PyThread_exit_thread(0);
}

88
void PyThread__exit_thread(void)
89 90 91 92 93
{
	do_PyThread_exit_thread(1);
}

#ifndef NO_EXIT_PROG
94
static void do_PyThread_exit_prog(int status, int no_cleanup)
95 96 97 98 99 100 101 102 103
{
	dprintf(("PyThread_exit_prog(%d) called\n", status));
	if (!initialized)
		if (no_cleanup)
			_exit(status);
		else
			exit(status);
}

104
void PyThread_exit_prog(int status)
105 106 107 108
{
	do_PyThread_exit_prog(status, 0);
}

109
void PyThread__exit_prog(int status)
110 111 112 113 114 115 116 117
{
	do_PyThread_exit_prog(status, 1);
}
#endif /* NO_EXIT_PROG */

/*
 * Lock support.
 */
118
PyThread_type_lock PyThread_allocate_lock(void)
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
{
	pth_lock *lock;
	int status, error = 0;

	dprintf(("PyThread_allocate_lock called\n"));
	if (!initialized)
		PyThread_init_thread();

	lock = (pth_lock *) malloc(sizeof(pth_lock));
        memset((void *)lock, '\0', sizeof(pth_lock));
	if (lock) {
		lock->locked = 0;
		status = pth_mutex_init(&lock->mut);
		CHECK_STATUS("pth_mutex_init");
		status = pth_cond_init(&lock->lock_released);
		CHECK_STATUS("pth_cond_init");
		if (error) {
			free((void *)lock);
			lock = NULL;
		}
	}
140
	dprintf(("PyThread_allocate_lock() -> %p\n", lock));
141 142 143
	return (PyThread_type_lock) lock;
}

144
void PyThread_free_lock(PyThread_type_lock lock)
145 146 147
{
	pth_lock *thelock = (pth_lock *)lock;

148
	dprintf(("PyThread_free_lock(%p) called\n", lock));
149 150 151 152

	free((void *)thelock);
}

153
int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
154 155 156 157 158
{
	int success;
	pth_lock *thelock = (pth_lock *)lock;
	int status, error = 0;

159
	dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag));
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

	status = pth_mutex_acquire(&thelock->mut, !waitflag, NULL);
	CHECK_STATUS("pth_mutex_acquire[1]");
	success = thelock->locked == 0;
        if (success) thelock->locked = 1;
        status = pth_mutex_release( &thelock->mut );
        CHECK_STATUS("pth_mutex_release[1]");

        if ( !success && waitflag ) {
                /* continue trying until we get the lock */

                /* mut must be locked by me -- part of the condition
                 * protocol */
                status = pth_mutex_acquire( &thelock->mut, !waitflag, NULL );
                CHECK_STATUS("pth_mutex_acquire[2]");
                while ( thelock->locked ) {
                        status = pth_cond_await(&thelock->lock_released,
                                                &thelock->mut, NULL);
                        CHECK_STATUS("pth_cond_await");
                }
                thelock->locked = 1;
                status = pth_mutex_release( &thelock->mut );
                CHECK_STATUS("pth_mutex_release[2]");
                success = 1;
        }
        if (error) success = 0;
186
        dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success));
187 188 189
	return success;
}

190
void PyThread_release_lock(PyThread_type_lock lock)
191 192 193 194
{
        pth_lock *thelock = (pth_lock *)lock;
        int status, error = 0;

195
        dprintf(("PyThread_release_lock(%p) called\n", lock));
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219

        status = pth_mutex_acquire( &thelock->mut, 0, NULL );
        CHECK_STATUS("pth_mutex_acquire[3]");

        thelock->locked = 0;

        status = pth_mutex_release( &thelock->mut );
        CHECK_STATUS("pth_mutex_release[3]");

        /* wake up someone (anyone, if any) waiting on the lock */
        status = pth_cond_notify( &thelock->lock_released, 0 );
        CHECK_STATUS("pth_cond_notify");
}

/*
 * Semaphore support.
 */

struct semaphore {
	pth_mutex_t mutex;
	pth_cond_t cond;
	int value;
};

220
PyThread_type_sema PyThread_allocate_sema(int value)
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
{
	struct semaphore *sema;
	int status, error = 0;

	dprintf(("PyThread_allocate_sema called\n"));
	if (!initialized)
		PyThread_init_thread();

	sema = (struct semaphore *) malloc(sizeof(struct semaphore));
	if (sema != NULL) {
		sema->value = value;
		status = pth_mutex_init(&sema->mutex);
		CHECK_STATUS("pth_mutex_init");
		status = pth_cond_init(&sema->cond);
		CHECK_STATUS("pth_mutex_init");
		if (error) {
			free((void *) sema);
			sema = NULL;
		}
	}
241
	dprintf(("PyThread_allocate_sema() -> %p\n",  sema));
242 243 244
	return (PyThread_type_sema) sema;
}

245
void PyThread_free_sema(PyThread_type_sema sema)
246 247 248
{
	struct semaphore *thesema = (struct semaphore *) sema;

249
	dprintf(("PyThread_free_sema(%p) called\n",  sema));
250 251 252
	free((void *) thesema);
}

253
int PyThread_down_sema(PyThread_type_sema sema, int waitflag)
254 255 256 257
{
	int status, error = 0, success;
	struct semaphore *thesema = (struct semaphore *) sema;

258
	dprintf(("PyThread_down_sema(%p, %d) called\n",  sema, waitflag));
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
	status = pth_mutex_acquire(&thesema->mutex, !waitflag, NULL);
	CHECK_STATUS("pth_mutex_acquire");
	if (waitflag) {
		while (!error && thesema->value <= 0) {
			status = pth_cond_await(&thesema->cond,
						&thesema->mutex, NULL);
			CHECK_STATUS("pth_cond_await");
		}
	}
	if (error)
		success = 0;
	else if (thesema->value > 0) {
		thesema->value--;
		success = 1;
	}
	else
		success = 0;
	status = pth_mutex_release(&thesema->mutex);
	CHECK_STATUS("pth_mutex_release");
278
	dprintf(("PyThread_down_sema(%p) return\n",  sema));
279 280 281
	return success;
}

282
void PyThread_up_sema(PyThread_type_sema sema)
283 284 285 286
{
	int status, error = 0;
	struct semaphore *thesema = (struct semaphore *) sema;

287
	dprintf(("PyThread_up_sema(%p)\n",  sema));
288 289 290 291 292 293 294 295
	status = pth_mutex_acquire(&thesema->mutex, 0, NULL);
	CHECK_STATUS("pth_mutex_acquire");
	thesema->value++;
	status = pth_cond_notify(&thesema->cond, 1);
	CHECK_STATUS("pth_cond_notify");
	status = pth_mutex_release(&thesema->mutex);
	CHECK_STATUS("pth_mutex_release");
}