File: mthread_posix.c

package info (click to toggle)
euslisp 9.31%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 55,448 kB
  • sloc: ansic: 41,610; lisp: 3,339; makefile: 286; sh: 238; asm: 138; python: 53
file content (497 lines) | stat: -rw-r--r-- 11,664 bytes parent folder | download
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
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
#if PTHREAD
#include "eus.h"
#define ESUCCESS 0

/*
 * Most functions in thread library of Solaris2 return Zero on success.
 */

/* thread function for POSIX Thread */
struct {
    int using;
    thread_t tid;
} thread_table[MAXTHREAD];

unsigned int thr_self()
{
    int i;
    thread_t tid;

    tid = pthread_self();
    for( i = 0; i < MAXTHREAD && !pthread_equal(thread_table[i].tid,tid); i++ )
      ;

    return( i );
}

int thr_getprio( int tid, int *prio )
{
    int policy,err;
    struct  sched_param param;
    err = pthread_getschedparam( thread_table[tid].tid, &policy, &param );
    if (err == 0){
      *prio = param.sched_priority;
      return ESUCCESS;
    }else
      return errno;
}

int thr_setprio(int tid, int prio)
{
    int err;
    struct  sched_param param;
    param.sched_priority = prio;
    err = pthread_setschedparam( thread_table[tid].tid, SCHED_RR, &param );
    if (err == 0)
      return ESUCCESS;
    else
      return errno;
}

struct thr_arg {
    int tid;
    void (*func)();
    void *args;
};

static void thr_cleanup( struct thr_arg *arg )
{
    thread_table[arg->tid].using = 0;

    free(arg);
}

static int thr_create_lock=0;

static void thr_startup( struct thr_arg *arg )
{
    //if (debug) printf( "thr_startup:tid=%d\n", arg->tid ); 
    /* this line causes SEGMENTATION FAULT, but why? R.Hanai */

  pthread_cleanup_push((void(*)(void *))thr_cleanup, arg );
    if( !thread_table[arg->tid].tid ) 
      thread_table[arg->tid].tid = pthread_self(); /* R.Hanai */

/*  Linuxthread is not supported */
#if !Linux && !Cygwin
    pthread_setcancel( CANCEL_ON );
    pthread_setasynccancel( CANCEL_ON );
#endif
    while(thr_create_lock) usleep(1000);
    (arg->func)( arg->args );

    pthread_cleanup_pop( 1 );
}

int thr_create(void *base, size_t size, void (*func)(void *), void *args, long flags, int *tid )
/* base is not used */
/* size is not implemented */
/* flags is not used */
{
    int i, stat;
    struct thr_arg *arg;

    for( i = 0; i < MAXTHREAD && thread_table[i].using; i++ )
      ;
    if( i >= MAXTHREAD )
      return -1;

    if( (arg = (struct thr_arg *)malloc( sizeof(struct thr_arg) )) == NULL )
      return -1;

    arg->tid = i;
    arg->func = func;
    arg->args = args;
    thr_create_lock=1;
    stat = pthread_create( &thread_table[i].tid, NULL, (void*(*)(void *))thr_startup, arg );
    if( stat == 0 )
      thread_table[i].using = 1;
    *tid = i;
    thr_create_lock=0;
    return( stat );
}

#if Linux
#include <signal.h>
/*
   thr_suspend() and thr_continue() are not implemented.
   these routines are only defined to avoid prototype definition error.
 */
pthread_mutex_t susp_the_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t susp_mut = PTHREAD_MUTEX_INITIALIZER;
volatile int susp_sentinel = 0;
pthread_once_t susp_once = PTHREAD_ONCE_INIT;
pthread_t susp_null_pthread = {0};
pthread_t susp_array[MAXTHREAD]; 
int susp_bottom = MAXTHREAD;
int susp_inited = 0;

/*
 * Handle SIGUSR1 in the target thread, to suspend it until
 * receiving SIGUSR2 (resume).
 */
void
suspend_signal_handler (int sig)
{
    sigset_t signal_set;

    /*
     * Block all signals except SIGUSR2 while suspended.
     */
    sigfillset (&signal_set);
    sigdelset (&signal_set, SIGUSR2);
    susp_sentinel = 1;
    sigsuspend (&signal_set);

    /*
     * Once I'm here, I've been resumed, and the resume signal
     * handler has been run to completion.
     */
    return;
}

/*
 * Handle SIGUSR2 in the target thread, to resume it. Note that
 * the signal handler does nothing. It exists only because we need
 * to cause sigsuspend() to return.
 */
void
resume_signal_handler (int sig)
{
    return;
}

/*
 * Dynamically initialize the "suspend package" when first used
 * (called by pthread_once).
 */
void
suspend_init_routine (void)
{
    int status;
    struct sigaction sigusr1, sigusr2;

    /*
     * Allocate the suspended threads array. This array is used
     * to guarentee idempotency
     */
    //susp_bottom = 10;
//    susp_array = (pthread_t*) calloc (susp_bottom, sizeof (pthread_t));

    /*
     * Install the signal handlers for suspend/resume.
     */
    sigusr1.sa_flags = 0;
    sigusr1.sa_handler = suspend_signal_handler;

    sigemptyset (&sigusr1.sa_mask);
    sigusr2.sa_flags = 0;
    sigusr2.sa_handler = resume_signal_handler;
    sigusr2.sa_mask = sigusr1.sa_mask;

    status = sigaction (SIGUSR1, &sigusr1, NULL);
    if (status == -1)
      {fprintf (stderr, "Installing suspend handler: %s\n", strerror(errno)); abort();}
    
    status = sigaction (SIGUSR2, &sigusr2, NULL);
    if (status == -1)
      {fprintf (stderr, "Installing resume handler : %s\n", strerror(errno)); abort(); }
    
    susp_inited = 1;
    return;
}

/*
 * Suspend a thread by sending it a signal (SIGUSR1), which will
 * block the thread until another signal (SIGUSR2) arrives.
 *
 * Multiple calls to thd_suspend for a single thread have no
 * additional effect on the thread -- a single thd_continue
 * call will cause it to resume execution.
 */
int 
//thd_suspend (pthread_t target_thread)
pthread_suspend (pthread_t target_thread)
{
    int status;
    int i = 0;

    /*
     * The first call to thd_suspend will initialize the
     * package.
     */
    status = pthread_once (&susp_once, suspend_init_routine);
    if (status != 0)
        return status;

    /* 
     * Serialize access to suspend, makes life easier
     */
    status = pthread_mutex_lock (&susp_mut);
    if (status != 0)
        return status;

    /*
     * Threads that are suspended are added to the target_array;
     * a request to suspend a thread already listed in the array
     * is ignored. Sending a second SIGUSR1 would cause the
     * thread to re-suspend itself as soon as it is resumed.
     */
    while (i < susp_bottom) 
        if (susp_array[i++] == target_thread) {
            status = pthread_mutex_unlock (&susp_mut);
            return status;
        }

    /*
     * Ok, we really need to suspend this thread. So, lets find
     * the location in the array that we'll use. If we run off
     * the end, realloc the array for more space.
     */
    i = 0;
    while (susp_array[i] != 0)
        i++;

    if (i == susp_bottom) {
//        susp_array = (pthread_t*) realloc (
//            susp_array, (++susp_bottom * sizeof (pthread_t)));
//        if (susp_array == NULL) {
            pthread_mutex_unlock (&susp_mut);
            return errno;
//        }

//        susp_array[susp_bottom] = susp_null_pthread;   /* Clear new entry */
    }

    /*
     * Clear the sentinel and signal the thread to suspend.
     */
    susp_sentinel = 0;
    status = pthread_kill (target_thread, SIGUSR1);
    if (status != 0) {
        pthread_mutex_unlock (&susp_mut);
        return status;
    }

    /*
     * Wait for the sentinel to change.
     */
    while (susp_sentinel == 0)
        sched_yield ();
    
    susp_array[i] = target_thread;

    status = pthread_mutex_unlock (&susp_mut);
    return status;
}

/*
 * Resume a suspended thread by sending it SIGUSR2 to break
 * it out of the sigsuspend() in which it's waiting. If the
 * target thread isn't suspended, return with success.
 */
int 
//thd_continue (pthread_t target_thread)
pthread_continue (pthread_t target_thread)
{
    int status;
    int i = 0;
    /* 
     * Serialize access to suspend, makes life easier
     */
    status = pthread_mutex_lock (&susp_mut);
    if (status != 0)
        return status;

    /*
     * If we haven't been initialized, then the thread must be "resumed"
     * it couldn't have been suspended!
     */
    if (!susp_inited) {
        status = pthread_mutex_unlock (&susp_mut);
        return status;
    }

    /*
     * Make sure the thread is in the suspend array. If not, it
     * hasn't been suspended (or it has already been resumed) and
     * we can just carry on.
     */
    while (susp_array[i] != target_thread && i < susp_bottom) 
        i++;

    if (i >= susp_bottom) {
        pthread_mutex_unlock (&susp_mut);
        return 0;
    }

    /*
     * Signal the thread to continue, and remove the thread from
     * the suspended array.
     */
    status = pthread_kill (target_thread, SIGUSR2);
    if (status != 0) {
        pthread_mutex_unlock (&susp_mut);
        return status;
    }

    susp_array[i] = 0;               /* Clear array element */
    status = pthread_mutex_unlock (&susp_mut);
    return status;
}
#endif
int thr_suspend( int tid ) { 
  return pthread_suspend ( thread_table[tid].tid );
}

int thr_continue( int tid ) {
  return pthread_continue ( thread_table[tid].tid );
}


int thr_kill( int tid, int sig )
/* sig is not used */
{
    if( pthread_cancel( thread_table[tid].tid ) < 0 )
      return errno;
    else
      return ESUCCESS;
}

/* readers/writer lock functions for PISIX Thread */
int rwlock_init(rwlock_t *rwlp, int type, void *arg)
{
    pthread_mutex_init(&(rwlp->lock), NULL);
    pthread_cond_init(&(rwlp->r_cond), NULL);
    pthread_cond_init(&(rwlp->w_cond), NULL);

    rwlp->readers = 0;

    return 0;
}

int rwlock_destroy( rwlock_t *rwlp )
{
    pthread_mutex_destroy( &(rwlp->lock) );
    pthread_cond_destroy( &(rwlp->r_cond) );
    pthread_cond_destroy( &(rwlp->w_cond) );

    return 0;
}

int rw_rdlock( rwlock_t *rwlp )
{
    pthread_mutex_lock( &(rwlp->lock) );
    while( rwlp->readers == (unsigned int)-1 )
      pthread_cond_wait( &(rwlp->r_cond), &(rwlp->lock) );
    rwlp->readers++;
    pthread_mutex_unlock( &(rwlp->lock) );

    return 0;
}

int rw_wrlock( rwlock_t *rwlp )
{
    pthread_mutex_lock( &(rwlp->lock) );
    while( rwlp->readers != 0 )
      pthread_cond_wait( &(rwlp->w_cond), &(rwlp->lock) );
    rwlp->readers=-1;
    pthread_mutex_unlock( &(rwlp->lock) );

    return 0;
}

int rw_unlock( rwlock_t *rwlp )
{
    pthread_mutex_lock( &(rwlp->lock) );
    if( rwlp->readers == (unsigned int)-1 )
      rwlp->readers = 0;
    else
      rwlp->readers--;
    pthread_cond_broadcast( &(rwlp->w_cond) );
    pthread_cond_broadcast( &(rwlp->r_cond) );
    pthread_mutex_unlock( &(rwlp->lock) );

    return 0;
}

/* semaphore function for POSIX Thread */
int sema_init(sema_t *sem, unsigned int c, int d, void *e)
/* c is not used */
/* d is not used */
/* e is not used */
{
  pthread_mutex_init(&(sem->lock), NULL);
  pthread_cond_init(&(sem->cond), NULL);
  sem->count = 0;

    return 0;
}

int sema_destroy(sema_t *sem)
{
  pthread_mutex_destroy(&(sem->lock));
  pthread_cond_destroy(&(sem->cond));

    return 0;
}

int sema_wait(sema_t *sem)
{
  pthread_mutex_lock(&(sem->lock));
  while (sem->count == 0){
    pthread_cond_wait(&(sem->cond), &(sem->lock));}
  sem->count--;
  pthread_mutex_unlock(&(sem->lock));

    return 0;
}

int sema_trywait(sema_t *sem)
{
  int ret;
  pthread_mutex_lock(&(sem->lock));
  if (sem->count == 0)
    ret = EBUSY;
  else{
    sem->count--;
    ret = 0;
  }
  pthread_mutex_unlock(&(sem->lock));
  return (ret);
}
  
int sema_post(sema_t *sem)
{
  pthread_mutex_lock(&(sem->lock));
  sem->count++;
  pthread_cond_broadcast(&(sem->cond));
  pthread_mutex_unlock(&(sem->lock));

    return 0;
}


void mthread_init( context *mainctx )
{
    int i;
    pthread_t tid;

    for( i = 0; i < MAXTHREAD; i++ )
      thread_table[i].using = 0;

    thread_table[0].tid = pthread_self();
    thread_table[0].using = 1;

    pthread_mutex_init(&mark_lock, NULL);
    pthread_mutex_init(&alloc_lock, NULL);
    pthread_mutex_init(&free_thread_lock, NULL);
    pthread_mutex_init(&qthread_lock, NULL);
    pthread_mutex_init(&qsort_lock, NULL);
    
    sema_init(&free_thread_sem, 0, 0, 0);
    rwlock_init(&gc_lock, 0, 0);
}


#endif