Subversion Repositories shark

Rev

Rev 1041 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
961 pj 1
/*
2
 * Project: S.Ha.R.K.
3
 *
4
 * Coordinators:
5
 *   Giorgio Buttazzo    <giorgio@sssup.it>
6
 *   Paolo Gai           <pj@gandalf.sssup.it>
7
 *
8
 * Authors     :
9
 *   Paolo Gai           <pj@gandalf.sssup.it>
10
 *   Massimiliano Giorgi <massy@gandalf.sssup.it>
11
 *   Luca Abeni          <luca@gandalf.sssup.it>
12
 *   (see the web pages for full authors list)
13
 *
14
 * ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
15
 *
16
 * http://www.sssup.it
17
 * http://retis.sssup.it
18
 * http://shark.sssup.it
19
 */
20
 
21
/**
22
 ------------
1043 tullio 23
 CVS :        $Id: sem.c,v 1.3 2006-06-12 12:29:34 tullio Exp $
961 pj 24
 
25
 File:        $File$
1043 tullio 26
 Revision:    $Revision: 1.3 $
27
 Last update: $Date: 2006-06-12 12:29:34 $
961 pj 28
 ------------
29
 
30
 This file contains the Hartik 3.3.1 Semaphore functions
31
 
32
 Author:      Giuseppe Lipari
33
 
34
 Semaphores:
35
 this is the generalized version of the primitives signal & wait
36
 In this case, the user can specify the number to inc/dec the
37
 semaphore's counter. It is useful in the buffer management
38
 (see port section)
39
 
40
**/
41
 
42
/*
43
 * Copyright (C) 2000 Paolo Gai
44
 *
45
 * This program is free software; you can redistribute it and/or modify
46
 * it under the terms of the GNU General Public License as published by
47
 * the Free Software Foundation; either version 2 of the License, or
48
 * (at your option) any later version.
49
 *
50
 * This program is distributed in the hope that it will be useful,
51
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
52
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
53
 * GNU General Public License for more details.
54
 *
55
 * You should have received a copy of the GNU General Public License
56
 * along with this program; if not, write to the Free Software
57
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
58
 *
59
 */
60
 
61
 
62
#include <stdarg.h>
63
#include <sem/sem/sem.h>
64
#include <kernel/config.h>
65
#include <ll/ll.h>
66
#include <ll/string.h>
67
#include <kernel/const.h>
68
#include <sys/types.h>
69
#include <kernel/descr.h>
70
#include <kernel/var.h>
71
#include <kernel/func.h>
72
#include <limits.h>
73
#include <fcntl.h>
74
 
75
#include <tracer.h>
76
 
77
/* Semaphores descriptor tables */
78
static struct sem_des {
79
    char *name;     /* a name, for named semaphores */
80
    int index;      /* an index for sem_open, containing the sem number */
81
    int count;      /* the semaphore counter */
82
    IQUEUE blocked; /* the blocked processes queue */
83
    int next;       /* the semaphore queue */
84
    BYTE used;      /* 1 if the semaphore is used */
85
} sem_table[SEM_NSEMS_MAX];
86
 
87
 
88
/* this -IS- an extension to the proc_table!!! */
89
static struct {
90
    int decsem;   /* the value required in sem_xwait */
91
    int sem;      /* the semaphore on whitch the process is blocked */
92
} sp_table[MAX_PROC];
93
 
94
static int free_sem;         /* Queue of free sem                    */
95
 
96
 
97
 
98
/*----------------------------------------------------------------------*/
99
/* Cancellation test for semaphores                                     */
100
/*----------------------------------------------------------------------*/
101
 
102
/* this is the test that is done when a task is being killed
103
   and it is waiting on a sigwait */
104
static int semwait_cancellation_point(PID i, void *arg)
105
{
106
    LEVEL l;
107
 
108
    if (proc_table[i].status == WAIT_SEM) {
109
      /* the task that have to be killed is waiting on a sig_wait.
110
         we reset the data structures set in sig_wait and then when the
111
         task will return on the sig_wait it will fall into a
112
         task_testcancel */
113
 
114
      /* extract the process from the semaphore queue... */
115
      iq_extract(i,&sem_table[ sp_table[i].sem ].blocked);
116
 
117
      l = proc_table[i].task_level;
118
      level_table[l]->public_unblock(l,i);
119
 
120
      return 1;
121
    }
122
 
123
    return 0;
124
}
125
 
126
/*----------------------------------------------------------------------*/
127
/* Init the semaphoric structures                                       */
128
/*----------------------------------------------------------------------*/
129
void SEM_register_module(void)
130
{
131
    int i;
132
 
133
    for (i = 0; i < SEM_NSEMS_MAX; i++) {
134
        sem_table[i].name = NULL;
135
        sem_table[i].index = i;
136
        sem_table[i].count = 0;
137
        iq_init(&sem_table[i].blocked, &freedesc, 0);
138
        sem_table[i].next = i+1;
139
        sem_table[i].used = 0;
140
    }
141
    sem_table[SEM_NSEMS_MAX-1].next = NIL;
142
    free_sem = 0;
143
 
144
    register_cancellation_point(semwait_cancellation_point, NULL);
145
}
146
 
147
/*----------------------------------------------------------------------*/
148
/* Allocate a semaphoric descriptor and sets the counter to n           */
149
/*----------------------------------------------------------------------*/
150
 
151
// the pshared parameter is NRQ for PSE52
152
int sem_init(sem_t *sem, int pshared, unsigned int value)
153
{
154
    SYS_FLAGS f;
155
 
156
    if (value > SEM_VALUE_MAX)
157
      return EINVAL;
158
 
159
    f = kern_fsave();
160
    *sem = free_sem;
161
    if (*sem != NIL) {
162
        free_sem = sem_table[*sem].next;
163
        sem_table[*sem].name = NULL;
164
        sem_table[*sem].count = value;
165
        iq_init(&sem_table[*sem].blocked, &freedesc, 0);
166
        sem_table[*sem].used = 1;
167
    }
168
    else {
169
        errno = ENOSPC;
170
        kern_frestore(f);
171
        return -1;
172
    }
173
    kern_frestore(f);
174
    return 0;
175
}
176
 
177
/*----------------------------------------------------------------------*/
178
/* Frees a semaphores descriptor                                        */
179
/*----------------------------------------------------------------------*/
180
int sem_destroy(sem_t *sem)
181
{
182
    SYS_FLAGS f;
183
 
184
    f = kern_fsave();
185
 
186
    if (*sem < 0 || *sem >= SEM_NSEMS_MAX || !sem_table[*sem].used) {
187
      errno = EINVAL;
188
      kern_frestore(f);
189
      return -1;
190
    }
191
 
192
    if (sem_table[*sem].blocked.first != NIL) {
193
      errno = EBUSY;
194
      kern_frestore(f);
195
      return -1;
196
    }
197
 
198
    sem_table[*sem].used = 0;
199
    sem_table[*sem].next = free_sem;
200
    free_sem = *sem;
201
 
202
    kern_frestore(f);
203
    return 0;
204
}
205
 
206
/*----------------------------------------------------------------------*/
207
/* Allocate a named semaphore                                           */
208
/*----------------------------------------------------------------------*/
209
 
210
// the pshared parameter is NRQ for PSE52
211
sem_t *sem_open(const char *name, int oflag, ...)
212
{
213
    int i, j;
214
    int found = 0;
215
    mode_t m;
216
    sem_t sem;
217
    SYS_FLAGS f;
218
 
219
    f = kern_fsave();
220
 
221
    for (i = 0; i < SEM_NSEMS_MAX; i++)
222
      if (sem_table[i].used) {
223
        if (strcmp(name, sem_table[i].name) == 0) {
224
          found = 1;
225
          break;
226
        }
227
      }
228
    if (found) {
229
      if (oflag == (O_CREAT | O_EXCL)) {
230
          errno = EEXIST;
231
          kern_frestore(f);
232
          return SEM_FAILED;
233
      } else {
234
          kern_frestore(f);
235
          return &sem_table[i].index;
236
      }
237
    } else {
238
      if (!(oflag & O_CREAT)) {
239
          errno = ENOENT;
240
          kern_frestore(f);
241
          return SEM_FAILED;
242
      } else {
243
          va_list l;
244
 
245
          va_start(l, oflag);
246
            m = va_arg(l,mode_t);
247
            j = va_arg(l, int);
248
          va_end(l);
249
 
250
          if (j > SEM_VALUE_MAX) {
251
            errno = EINVAL;
252
            kern_frestore(f);
253
            return SEM_FAILED;
254
          }
255
 
256
          sem = free_sem;
257
          if (sem != -1) {
258
            free_sem = sem_table[sem].next;
259
            sem_table[sem].name = kern_alloc(strlen((char *)name)+1);
260
            strcpy(sem_table[sem].name, (char *)name);
261
            sem_table[sem].count = j;
262
            iq_init(&sem_table[sem].blocked, &freedesc, 0);
263
            sem_table[sem].used = 1;
264
            kern_frestore(f);
265
            return &sem_table[sem].index;
266
          }
267
          else {
268
            errno = ENOSPC;
269
            kern_frestore(f);
270
            return SEM_FAILED;
271
          }
272
      }
273
    }
274
}
275
 
276
/*----------------------------------------------------------------------*/
277
/* Frees a named semaphore                                              */
278
/*----------------------------------------------------------------------*/
279
int sem_close(sem_t *sem)
280
{
281
    SYS_FLAGS f;
282
 
283
    f = kern_fsave();
284
 
285
    if (*sem < 0 || *sem >= SEM_NSEMS_MAX || !sem_table[*sem].used) {
286
      errno = EINVAL;
287
      kern_frestore(f);
288
      return -1;
289
    }
290
 
291
/*  why not???
292
    if (sem_table[*sem].q_first != -1) {
293
      errno = EBUSY;
294
      kern_sti();
295
      return -1;
296
    } */
297
 
298
    kern_free(sem_table[*sem].name,strlen(sem_table[*sem].name)+1);
299
    sem_table[*sem].used = 0;
300
    sem_table[*sem].next = free_sem;
301
    free_sem = *sem;
302
 
303
    kern_frestore(f);
304
    return 0;
305
}
306
 
307
/*----------------------------------------------------------------------*/
308
/* Unlink a named semaphore                                             */
309
/*----------------------------------------------------------------------*/
310
int sem_unlink(const char *name)
311
{
312
    int i;
313
    int found = 0;
314
    SYS_FLAGS f;
315
 
316
    f = kern_fsave();
317
 
318
    for (i = 0; i < SEM_NSEMS_MAX; i++)
319
      if (sem_table[i].used) {
320
        if (strcmp(name, sem_table[i].name) == 0) {
321
          found = 1;
322
        }
323
      }
324
 
325
    if (found) {
326
      kern_free(sem_table[i].name,strlen((char *)name)+1);
327
      sem_table[i].used = 0;
328
      sem_table[i].next = free_sem;
329
      free_sem = i;
330
      kern_frestore(f);
331
      return 0;
332
    } else {
333
      errno = ENOENT;
334
      kern_frestore(f);
335
      return SEM_FAILED;
336
    }
337
}
338
 
339
/*----------------------------------------------------------------------*/
340
/* Generic wait. If it is possible, decrements the sem counter of n,    */
341
/* else blocks the task.                                                */
342
/*----------------------------------------------------------------------*/
343
int sem_wait(sem_t *s)
344
{
345
    struct sem_des *s1; /* It speeds up access */
346
 
347
    if (*s < 0 || *s >= SEM_NSEMS_MAX || !sem_table[*s].used) {
348
      errno = EINVAL;
349
      return -1;
350
    }
351
 
352
    task_testcancel();
353
 
354
    proc_table[exec_shadow].context = kern_context_save();
355
 
356
    s1 = &sem_table[*s];
357
 
358
    if (s1->blocked.first != NIL || s1->count == 0)  {
359
            /* We must block exec task   */
360
            LEVEL l;            /* for readableness only */
361
 
362
            /* tracer stuff */
363
            TRACER_LOGEVENT(FTrace_EVT_set_mutex_wait,(unsigned short int)proc_table[exec_shadow].context,(unsigned int)*s);
364
 
365
            kern_epilogue_macro();
366
 
367
            l = proc_table[exec_shadow].task_level;
368
            level_table[l]->public_block(l,exec_shadow);
369
 
370
            /* we insert the task in the semaphore queue */
371
            proc_table[exec_shadow].status = WAIT_SEM;
372
 
373
            /* Prepare sem_table des... */
374
            sp_table[exec_shadow].decsem = 1;
375
            sp_table[exec_shadow].sem = *s;
376
 
377
            /* ...and put it in sem queue */
378
            iq_insertlast(exec_shadow,&s1->blocked);
379
 
380
            /* and finally we reschedule */
381
            exec = exec_shadow = -1;
382
            scheduler();
383
            kern_context_load(proc_table[exec_shadow].context);
384
 
385
            /* sem_wait is a cancellation point... */
386
            task_testcancel();
387
    }
388
    else {
389
            s1->count--;
390
            /* tracer stuff */
391
            TRACER_LOGEVENT(FTrace_EVT_set_mutex_wait,(unsigned short int)proc_table[exec_shadow].context,(unsigned int)*s);
392
            kern_context_load(proc_table[exec_shadow].context);
393
    }
394
 
395
    return 0;
396
}
397
 
398
/*----------------------------------------------------------------------*/
399
/* Non-blocking wait                                                    */
400
/*----------------------------------------------------------------------*/
401
int sem_trywait(sem_t *s)
402
{
403
    struct sem_des *s1; /* It speeds up access */
404
    SYS_FLAGS f;
405
 
406
    if (*s < 0 || *s >= SEM_NSEMS_MAX || !sem_table[*s].used) {
407
      errno = EINVAL;
408
      return -1;
409
    }
410
 
411
    f = kern_fsave();
412
 
413
    s1 = &sem_table[*s];
414
 
415
    if (s1->blocked.first != NIL || s1->count == 0)  {
416
      errno = EAGAIN;
417
      kern_frestore(f);
418
      return -1;
419
    }
420
    else
421
      s1->count--;
422
 
423
    kern_frestore(f);
424
    return 0;
425
}
426
 
427
 
428
/*----------------------------------------------------------------------*/
429
/* Generic wait. If it is possible, decrements the sem counter of n,    */
430
/* else blocks the task.                                                */
431
/*----------------------------------------------------------------------*/
432
int sem_xwait(sem_t *s, int n, int wait)
433
{
434
    struct sem_des *s1; /* It speeds up access */
435
 
436
    if (*s < 0 || *s >= SEM_NSEMS_MAX || !sem_table[*s].used) {
437
      errno = EINVAL;
438
      return -1;
439
    }
440
 
441
    /* We do not need to save context if we are sure we shall not block! */
442
    if (wait == NON_BLOCK)
443
      kern_cli();
444
    else
445
      proc_table[exec_shadow].context = kern_context_save();
446
 
447
    s1 = &sem_table[*s];
448
 
449
    /* The non blocking wait is really simple! */
450
    /* We do not suspend or schedule anything  */    
451
    if (wait == NON_BLOCK) {
452
      if (s1->blocked.first != NIL || s1->count < n)  {
453
        errno = EAGAIN;
454
        kern_sti();
455
        return -1;
456
      }
457
      else
458
        s1->count -= n;
459
 
460
      kern_sti();
461
      return 0;
462
    }
463
    /* The blocking wait is more complex... */
464
    else {
465
        /* the blocking wait is a cancellation point */
466
        task_testcancel();
467
 
468
        if (s1->blocked.first != NIL || s1->count < n)  {
469
                    /* We must block exec task   */
470
                    LEVEL l;            /* for readableness only */
471
 
472
                    /* tracer */
473
                    TRACER_LOGEVENT(FTrace_EVT_set_mutex_wait,(unsigned short int)proc_table[exec_shadow].context,(unsigned int)*s);
474
 
475
                    kern_epilogue_macro();
476
 
477
                    l = proc_table[exec_shadow].task_level;
478
                    level_table[l]->public_block(l,exec_shadow);
479
 
480
                    /* we insert the task in the semaphore queue */
481
                    proc_table[exec_shadow].status = WAIT_SEM;
482
 
483
                    /* Prepare sem_table des... */
484
                    sp_table[exec_shadow].decsem = n;
485
                    sp_table[exec_shadow].sem = *s;
486
 
487
                    /* ...and put it in sem queue */
488
                    iq_insertlast(exec_shadow,&s1->blocked);
489
 
490
                    /* and finally we reschedule */
491
                    exec = exec_shadow = -1;
492
                    scheduler();
493
                    kern_context_load(proc_table[exec_shadow].context);
494
 
495
                    /* sem_wait is a cancellation point... */
496
                    task_testcancel();
497
            }
498
            else {
499
                    s1->count -= n;
500
                    /* tracer */
501
                    TRACER_LOGEVENT(FTrace_EVT_set_mutex_wait,(unsigned short int)proc_table[exec_shadow].context,(unsigned int)*s);
502
                    kern_context_load(proc_table[exec_shadow].context);
503
            }
504
    }
505
 
506
    return 0;
507
}
508
 
509
/*----------------------------------------------------------------------*/
510
/* Generic signal. It increments the sem counter of 1, and wakes one    */
511
/* of the tasks that are blocked on the semaphore, if it is possible.The*/
512
/* semaphoric queue is a FIFO queue, in order to eliminate deadlocks    */
513
/*----------------------------------------------------------------------*/
514
int sem_post(sem_t *s)
515
{
516
    struct sem_des *s1;        /* it speeds up access          */
517
    int p;                     /* idem                         */
518
    LEVEL l;
519
 
520
    if (*s < 0 || *s >= SEM_NSEMS_MAX || !sem_table[*s].used) {
521
      errno = EINVAL;
522
      return -1;
523
    }
524
 
525
    // ugly patch to call a sem_post!!!
526
    if (ll_ActiveInt()) {
527
      SYS_FLAGS f;
528
      f = kern_fsave();
529
      s1 = &sem_table[*s];
530
      s1->count ++;              /* inc sem count                */
531
 
532
      p = s1->blocked.first;
533
      if (p != NIL && sp_table[p].decsem <= s1->count) {
534
        /* Dec sem count */
535
        s1->count -= sp_table[p].decsem;
536
 
537
        /* Get task from blocked queue */
538
        iq_extract(p,&s1->blocked);
539
 
540
        l = proc_table[p].task_level;
541
        level_table[l]->public_unblock(l,p);
542
        /* only a task can be awaken */
543
        /* Preempt if necessary */
544
        event_need_reschedule();
545
      }
546
 
547
      /* tracer */
1041 tullio 548
      TRACER_LOGEVENT(FTrace_EVT_set_mutex_post,(unsigned short int)proc_table[exec_shadow].context,(unsigned int)*s);
961 pj 549
      kern_frestore(f);
550
    }
551
    else {
552
      proc_table[exec].context = kern_context_save();
553
 
554
      s1 = &sem_table[*s];
555
      s1->count ++;              /* inc sem count                */
556
 
557
      p = s1->blocked.first;
558
      if (p != NIL && sp_table[p].decsem <= s1->count) {
559
        /* Dec sem count */
560
        s1->count -= sp_table[p].decsem;
561
 
562
        /* Get task from blocked queue */
563
        iq_extract(p,&s1->blocked);
564
 
565
        l = proc_table[p].task_level;
566
        level_table[l]->public_unblock(l,p);
567
        /* only a task can be awaken */
568
        /* Preempt if necessary */
569
        scheduler();
570
      }
571
 
572
      /* tracer */
1041 tullio 573
      TRACER_LOGEVENT(FTrace_EVT_set_mutex_post,(unsigned short int)proc_table[exec_shadow].context,(unsigned int)*s);
961 pj 574
 
575
      kern_context_load(proc_table[exec_shadow].context);
576
    }
577
 
578
    return 0;
579
}
580
 
581
/*----------------------------------------------------------------------*/
582
/* Generic signal. It increments the sem counter of n, and wakes all the*/
583
/* tasks that are blocked on the semaphore, if it is possible. The      */
584
/* semaphoric queue is a FIFO queue, in order to eliminate deadlocks    */
585
/*----------------------------------------------------------------------*/
586
int sem_xpost(sem_t *s, int n)
587
{
588
    struct sem_des *s1;        /* it speeds up access          */
589
    int p;                     /* idem                         */
590
    int fl = 0;                /* a flag                       */
591
    LEVEL l;
592
 
593
    if (*s < 0 || *s >= SEM_NSEMS_MAX || !sem_table[*s].used) {
594
      errno = EINVAL;
595
      return -1;
596
    }
597
 
598
    // ugly patch to call a sem_post!!!
599
    if (ll_ActiveInt()) {      
600
      SYS_FLAGS f;
601
      f = kern_fsave();
602
      s1 = &sem_table[*s];
603
      s1->count += n;                     /* inc sem count                */
604
 
605
      p = s1->blocked.first;
606
      while (p != NIL && sp_table[p].decsem <= s1->count) {
607
        /* Dec sem count */
608
        s1->count -= sp_table[p].decsem;
609
 
610
        /* Get task from blocked queue */
611
        iq_extract(p,&s1->blocked);
612
 
613
        l = proc_table[p].task_level;
614
        level_table[l]->public_unblock(l,p);
615
 
616
        /* Next task to wake            */
617
        p = s1->blocked.first;
618
 
619
        fl = 1;
620
      }
621
 
622
      /* tracer */
1043 tullio 623
      TRACER_LOGEVENT(FTrace_EVT_set_mutex_post,(unsigned short int)proc_table[exec_shadow].context,(unsigned int)*s);
961 pj 624
 
625
      /* Preempt if necessary */
626
      if (fl) event_need_reschedule();
627
      kern_frestore(f);
628
    }
629
    else {
630
      proc_table[exec].context = kern_context_save();
631
 
632
      s1 = &sem_table[*s];
633
      s1->count += n;                     /* inc sem count                */
634
 
635
      p = s1->blocked.first;
636
      while (p != NIL && sp_table[p].decsem <= s1->count) {
637
        /* Dec sem count */
638
        s1->count -= sp_table[p].decsem;
639
 
640
        /* Get task from blocked queue */
641
        iq_extract(p,&s1->blocked);
642
 
643
        l = proc_table[p].task_level;
644
        level_table[l]->public_unblock(l,p);
645
 
646
        /* Next task to wake            */
647
        p = s1->blocked.first;
648
 
649
        fl = 1;
650
      }
651
 
652
      /* tracer */
1043 tullio 653
      TRACER_LOGEVENT(FTrace_EVT_set_mutex_post,(unsigned short int)proc_table[exec_shadow].context,(unsigned int)*s);
961 pj 654
 
655
      /* Preempt if necessary */
656
      if (fl) scheduler();
657
 
658
      kern_context_load(proc_table[exec_shadow].context);
659
    }
660
 
661
    return 0;
662
}
663
 
664
/*----------------------------------------------------------------------*/
665
/* Getvalue returns the value of the semaphore (>=0). If someone is     */
666
/* blocked on the semaphore, return the number of process blocked (<0)  */
667
/*----------------------------------------------------------------------*/
668
int sem_getvalue(sem_t *sem, int *sval)
669
{
670
    PID p;
671
    SYS_FLAGS f;
672
 
673
    if (*sem < 0 || *sem >= SEM_NSEMS_MAX || !sem_table[*sem].used) {
674
      errno = EINVAL;
675
      return -1;
676
    }
677
 
678
    f = kern_fsave();
679
 
680
    if (iq_isempty(&sem_table[*sem].blocked))
681
      /* the sem is free */
682
      *sval = sem_table[*sem].count;
683
    else {
684
      /* the sem is busy */
685
      *sval = 0;
686
      p = iq_query_first(&sem_table[*sem].blocked);
687
      do {
688
        (*sval)--;
689
        p = iq_query_next(p, &sem_table[*sem].blocked);
690
      } while (p != NIL);
691
    }
692
 
693
    kern_frestore(f);
694
    return 0;
695
}
696
 
697
 
698
/*----------------------------------------------------------------------*/
699
/* this function returns 1 if the task is blocked on a semaphore        */
700
/*----------------------------------------------------------------------*/
701
int isBlocked(PID i)
702
{
703
    if (proc_table[i].status == WAIT_SEM) return 1;
704
    else return 0;
705
}
706