source: svn/trunk/zas_dstar/hal/os/src/v2lin/lsemLib.c @ 2

Last change on this file since 2 was 2, checked in by phkim, 11 years ago

1.phkim

  1. revision copy newcon3sk r27
File size: 25.2 KB
Line 
1/****************************************************************************
2 *_Copyright (C) 2004, 2005, 2006 v2lin Team <http://v2lin.sf.net>
3 *_Copyright (C) 2000,2001  Monta Vista Software Inc.
4 *
5 * This file is part of the v2lin Library.
6 * VxWorks is a registered trademark of Wind River Systems, Inc.
7 *
8 * Initial implementation Gary S. Robertson, 2000, 2001.
9 * Contributed by Andrew Skiba, skibochka@sourceforge.net, 2004.
10 * Contributed by Mike Kemelmakher, mike@ubxess.com, 2005.
11 * Contributed by Constantine Shulyupin, conan.sh@gmail.com, 2006.
12 *
13 * The v2lin library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
17 *
18 * The v2lin Library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 * Lesser General Public License for more details.
22 *
23 ****************************************************************************/
24
25#define FIX_PTHREAD_COND_BUG    0
26
27#include <errno.h>
28#include <unistd.h>
29#include <stdlib.h>
30#include <stdio.h>
31#include <string.h>
32#include <signal.h>
33#include <semaphore.h>
34#include <sys/time.h>
35#include "v2lpthread.h"
36#include "vxw_defs.h"
37#include "internal.h"
38#include <assert.h>
39#include "v2ldebug.h"
40#include "vxw_hdrs.h"
41#include <pthread.h>
42
43#include "dsthalcommon.h"
44#include "dstoslayer.h"
45#include "os.h"
46#include "os_prive.h"
47
48#define SEM_OPT_MASK       0x0f
49#define SEM_TYPE_MASK      0xf0
50
51#define BINARY_SEMA4       0x10
52#define MUTEX_SEMA4        0x20
53#define COUNTING_SEMA4     0x40
54
55#define SEND  0
56#define FLUSH 1
57#define KILLD 2
58
59#if 0
60___Semaphore_APIs___()
61#endif
62/*****************************************************************************
63**  Control block for v2pthread semaphore
64**
65**  The basic POSIX semaphore does not provide for time-bounded waits nor
66**  for selection of a thread to ready based either on FIFO or PRIORITY-based
67**  waiting.  This 'wrapper' extends the POSIX pthreads semaphore to include
68**  the attributes of a v2pthread semaphore.
69**
70*****************************************************************************/
71
72static v2lsem_t *sem_list;
73
74static pthread_mutex_t sem_list_lock = PTHREAD_MUTEX_INITIALIZER;
75
76void semShow(v2lsem_t *s, FILE * out, int mem)
77{
78        DS_TASK_T *t;
79        fprintf(out,"o:%x ", (int)s->current_owner);
80        if (s->current_owner) { 
81            t = taskFind(s->current_owner, 1);
82                if (!t) // task not found
83                        fprintf(out,"<deleted> ");
84                else fprintf(out,"%s ", t->name);
85        }
86        fprintf(out,"rl:%i ",s->recursion_level);
87        fprintf(out,"tc:%i ",s->token_count);
88        fprintf(out,"(");
89        for ( t = s->first_susp; t; t = t->nxt_susp ) {
90                fprintf(out,"%x ",(int)t);
91                fprintf(out,"%s ",t->name);
92        }
93        fprintf(out,") ");
94        fprintf(out,"%x ",s->send_type);
95
96    fprintf(out,"%c ", s->flags & BINARY_SEMA4 ? 'B' : s->flags & MUTEX_SEMA4 ? 'M' : s->flags & COUNTING_SEMA4 ? 'C' : 'u' );
97        if ( mem ) {
98                int * i;
99                for ( i = (int*)s; i < (int*) (s+1);i++) 
100                        fprintf(out,"%x ",*i);
101        }
102        fprintf(out,"\n");
103}
104
105int semList(FILE * out, int mem)
106{
107        int c=0;
108        TRACEF();
109        v2lsem_t *s = sem_list;
110        while (s) {
111                c++;
112                fprintf(out,"%i %x: ",c, (int)s);
113                semShow(s,out,mem);
114                s=s->nxt_sem;
115        }
116        return c;
117}
118
119
120/*****************************************************************************
121**  sem_find_lock - verifies whether the specified semaphore still exists, and if
122**                so, locks exclusive access to the semaphore for the caller.
123*****************************************************************************/
124static int sem_find_lock(v2lsem_t * sem)
125{
126    int b_found = 0;
127        v2lsem_t *current_smcb;
128
129        //pthread_cleanup_push((void (*)(void *)) pthread_mutex_unlock, (void *) &sem_list_lock);
130        pthread_mutex_lock(&sem_list_lock);
131
132        for (current_smcb = sem_list; current_smcb != NULL; current_smcb = current_smcb->nxt_sem) {
133                if (current_smcb == sem) {
134                        /*
135                         ** Lock mutex for semaphore access (it is assumed that a
136                         ** 'pthread_cleanup_push()' has already been performed
137                         **  by the caller in case of unexpected thread termination.)
138                         */
139                        pthread_mutex_lock(&(sem->sem_lock));
140                        b_found = 1;
141                        break;
142                }
143        }
144
145        pthread_mutex_unlock(&sem_list_lock);
146        //pthread_cleanup_pop(0);
147
148    if ( b_found == 0 )
149    {
150        fprintf(stderr, "|%s:%d| ERROR.\n", __FUNCTION__, __LINE__);
151        return 0;
152    }
153   
154        return current_smcb != NULL;
155}
156
157
158/*****************************************************************************
159** link_smcb - appends a new semaphore control block pointer to the sem_list
160*****************************************************************************/
161static void link_smcb(v2lsem_t * new_sem)
162{
163        v2lsem_t **i;
164
165        //pthread_cleanup_push((void (*)(void *)) pthread_mutex_unlock, (void *) &sem_list_lock);
166        pthread_mutex_lock(&sem_list_lock);
167
168        new_sem->nxt_sem = (v2lsem_t *) NULL;
169        i = &sem_list;
170        while (*i) i =& (*i)->nxt_sem;
171        *i=new_sem;
172        pthread_mutex_unlock(&sem_list_lock);
173        //pthread_cleanup_pop(0);
174}
175
176/*****************************************************************************
177** unlink_smcb - removes a semaphore control block pointer from the sem_list
178*****************************************************************************/
179static void unlink_smcb(v2lsem_t * smid)
180{
181        v2lsem_t **i =  & sem_list;
182
183        //pthread_cleanup_push((void (*)(void *)) pthread_mutex_unlock, (void *) &sem_list_lock);
184        pthread_mutex_lock(&sem_list_lock);
185        while (*i) {
186                if ( *i == smid ) {
187                        TRACEF("%p", smid);
188                        *i = (*i)->nxt_sem;     // remove
189                        break;
190                }
191                i = &((*i)->nxt_sem);
192        }
193        pthread_mutex_unlock(&sem_list_lock);
194        //pthread_cleanup_pop(0);
195}
196
197/*****************************************************************************
198** new_sem - creates a new v2pthread semaphore using pthreads resources
199*****************************************************************************/
200v2lsem_t *new_sem(int count)
201{
202        v2lsem_t *semaphore;
203 
204        semaphore = (v2lsem_t *) malloc(sizeof(v2lsem_t));
205        if (! semaphore ) {
206                return NULL;
207        }
208
209        memset(semaphore,0,sizeof(v2lsem_t));
210        semaphore->token_count = count;
211
212        /*
213         ** Mutex and Condition variable for semaphore send/pend
214         */
215#if 1
216        pthread_mutex_init(&semaphore->sem_lock, NULL);
217        pthread_cond_init(&semaphore->sem_send, NULL);
218
219        pthread_mutex_init(&semaphore->smdel_lock, NULL);
220        pthread_cond_init(&semaphore->smdel_cplt, NULL);
221#else
222    memcpy( &semaphore->sem_lock, &initmutex, sizeof(initmutex) );
223    memcpy( &semaphore->sem_send, &initcond, sizeof(initcond) );
224
225    memcpy( &semaphore->smdel_lock, &initmutex, sizeof(initmutex) );
226    memcpy( &semaphore->smdel_cplt, &initcond, sizeof(initcond) );
227#endif   
228
229        semaphore->send_type = SEND;
230        semaphore->recursion_level = 0;
231        semaphore->current_owner = 0;
232        semaphore->first_susp =  NULL;
233
234        return semaphore;
235}
236
237/*****************************************************************************
238** semBCreate - creates a v2pthread binary semaphore
239*****************************************************************************/
240v2lsem_t *semBCreate(int opt, int initial_state)
241{
242        v2lsem_t *semaphore;
243
244        if ((opt & SEM_Q_PRIORITY)
245                        || (opt & SEM_DELETE_SAFE)
246                        || (opt & SEM_INVERSION_SAFE)) {
247                errno = ENOSYS;
248                return (NULL);
249        }
250
251        if (initial_state == 0)
252                semaphore = new_sem(0);
253        else
254                semaphore = new_sem(1);
255
256        if (! semaphore ) return NULL;
257        TRACEF("%x %#x %x", (int)semaphore,(int)opt, (int)initial_state);
258
259        semaphore->flags = (opt & SEM_Q_PRIORITY) | BINARY_SEMA4;
260
261        link_smcb(semaphore);
262        return semaphore;
263}
264
265/*****************************************************************************
266** semCCreate - creates a v2pthread counting semaphore
267*****************************************************************************/
268v2lsem_t *semCCreate(int opt, int initial_count)
269{
270        v2lsem_t *semaphore;
271
272        if ((opt & SEM_Q_PRIORITY)
273                        || (opt & SEM_DELETE_SAFE)
274                        || (opt & SEM_INVERSION_SAFE)) {
275                errno = ENOSYS;
276                return (NULL);
277        }
278
279        semaphore = new_sem(initial_count);
280
281        if (! semaphore ) return NULL;
282        TRACEF("Creating counting semaphore - id %p", semaphore);
283
284        semaphore->flags = (opt & SEM_Q_PRIORITY) | COUNTING_SEMA4;
285
286        link_smcb(semaphore);
287
288        return semaphore;
289}
290
291/*****************************************************************************
292** semMCreate - creates a v2pthread mutual exclusion semaphore
293*****************************************************************************/
294v2lsem_t *semMCreate(int opt)
295{
296        v2lsem_t *semaphore;
297
298        if ((opt & SEM_Q_PRIORITY)
299                        || (opt & SEM_DELETE_SAFE)
300                        || (opt & SEM_INVERSION_SAFE)) {
301                TRACEF("WARNING not implemented");
302                errno = ENOSYS;
303                return (NULL);
304        }
305        semaphore = new_sem(1);
306
307        if ( ! semaphore ) return NULL;
308        TRACEF("Creating mutex semaphore - id %p", semaphore);
309
310        semaphore->flags = (opt & SEM_OPT_MASK) | MUTEX_SEMA4;
311
312        link_smcb(semaphore);
313
314        return semaphore;
315}
316
317/*****************************************************************************
318** semDelete - removes the specified semaphore from the semaphore list and
319**             frees the memory allocated for the semaphore control block.
320*****************************************************************************/
321STATUS semDelete(v2lsem_t * semaphore)
322{
323        STATUS error = OK;
324
325        //pthread_cleanup_push((void (*)(void *)) pthread_mutex_unlock, &semaphore->sem_lock);
326        if (! sem_find_lock(semaphore)) {
327                error = S_objLib_OBJ_ID_ERROR;  /* Invalid semaphore specified */
328                goto exit;
329        }
330        TRACEF("task @ %x delete semaphore @ %x", (int)OS_GetSelfTaskId(), (int)semaphore);
331        //  Send signal and block while any tasks are still waiting on the semaphore
332//      taskLock();
333        if (semaphore->first_susp !=  NULL) {
334                TRACEF("isemDelete - tasks pending on semaphore list @ %p", semaphore->first_susp);
335                // Lock mutex for semaphore delete completion
336                //pthread_cleanup_push((void (*)(void *)) pthread_mutex_unlock, &semaphore->smdel_lock);
337                pthread_mutex_lock(&(semaphore->smdel_lock));
338
339                semaphore->send_type = KILLD;
340
341                pthread_cond_broadcast(&(semaphore->sem_send));
342
343                pthread_mutex_unlock(&(semaphore->sem_lock));
344
345                /*
346                 **  Wait for all pended tasks to receive delete message.
347                 **  The last task to receive the message will signal the
348                 **  delete-complete condition variable.
349                 */
350                while (semaphore->first_susp != (DS_TASK_T *) NULL)
351                        pthread_cond_wait(&(semaphore->smdel_cplt), &(semaphore->smdel_lock));
352
353                //pthread_cleanup_pop(0);
354        }
355
356        unlink_smcb(semaphore);
357        free((void *) semaphore);
358//      taskUnlock();
359
360        exit:
361        {}
362        //pthread_cleanup_pop(0);
363
364        if (error != OK) {
365                errno = (int) error;
366                error = ERROR;
367        }
368        return error;
369}
370
371/*****************************************************************************
372** semFlush - unblocks all tasks waiting on the specified semaphore
373*****************************************************************************/
374STATUS semFlush(v2lsem_t * semaphore)
375{
376        STATUS error = OK;
377        TRACEF("%x", (int)semaphore);
378        //pthread_cleanup_push((void (*)(void *)) pthread_mutex_unlock, &semaphore->sem_lock);
379        if (!sem_find_lock(semaphore)) {
380                error = S_objLib_OBJ_ID_ERROR;  /* Invalid semaphore specified */
381                goto exit;
382        }
383        if ((semaphore->flags & SEM_TYPE_MASK) == MUTEX_SEMA4) {
384                error = S_semLib_INVALID_OPERATION;     /* Flush invalid for mutex */
385                pthread_mutex_unlock(&semaphore->sem_lock);
386                goto exit;
387        }
388        TRACEF("task @ %x flush semaphore list @ %x", (int)OS_GetSelfTaskId(), (int)&(semaphore->first_susp));
389        /*
390         **  Send signal and block while any tasks are still waiting
391         **  on the semaphore
392         */
393        //taskLock();
394        if (semaphore->first_susp ) {
395                // Lock mutex for semaphore delete completion
396                //pthread_cleanup_push((void (*)(void *)) pthread_mutex_unlock, &semaphore->smdel_lock);
397                pthread_mutex_lock(&(semaphore->smdel_lock));
398
399                semaphore->send_type = FLUSH;
400                pthread_cond_broadcast(&semaphore->sem_send);
401                pthread_mutex_unlock(&semaphore->sem_lock);
402
403                /*
404                 **  Wait for all pended tasks to receive delete message.
405                 **  The last task to receive the message will signal the
406                 **  delete-complete condition variable.
407                 */
408                while (semaphore->first_susp != NULL)
409                        pthread_cond_wait(&(semaphore->smdel_cplt), &(semaphore->smdel_lock));
410
411                pthread_mutex_unlock(&(semaphore->smdel_lock));
412                //pthread_cleanup_pop(0);
413        }
414        // TODO ??? else pthread_mutex_unlock(&(semaphore->sem_lock));
415        //taskUnlock();
416exit:
417        {}
418        //pthread_cleanup_pop(0);
419
420        if (error != OK) {
421                errno = (int) error;
422                error = ERROR;
423        }
424
425        return error;
426}
427
428/*****************************************************************************
429** semGive - releases a v2pthread semaphore token and awakens the first
430**           selected task waiting on the semaphore.
431*****************************************************************************/
432STATUS semGive(v2lsem_t * semaphore)
433{
434        STATUS error = OK;
435
436    SysASSERT( semaphore );
437       
438        //pthread_cleanup_push((void (*)(void *)) pthread_mutex_unlock, &semaphore->sem_lock);
439
440        if (! sem_find_lock(semaphore)) {
441                TRACEF("WARNING not found %x",(int)semaphore);
442                error = S_objLib_OBJ_ID_ERROR;
443                goto exit;
444        }
445        TRACEF("%x %i %i", (int)semaphore, (int)semaphore->recursion_level, (int)semaphore->token_count);
446        //  If semaphore is a mutex, make sure we own it before giving up the token.
447        if (((semaphore->flags & SEM_TYPE_MASK) == MUTEX_SEMA4) &&
448                        (semaphore->current_owner != OS_GetSelfTaskId())) {
449                error = S_semLib_INVALID_OPERATION;     
450                goto unlock;
451        }
452
453        /*
454         **  Either semaphore isn't a mutex or we currently own the mutex.
455         **  If semaphore is a mutex, recursion level should be > zero.
456         **  In this case, decrement recursion level, and if level == zero
457         **  after decrement, relinquish mutex ownership.
458         */
459        //TRACEF("Semaphore list @ %p recursion level = %d", &semaphore->first_susp, semaphore->recursion_level);
460        if (semaphore->recursion_level > 0) {
461                --semaphore->recursion_level;
462                if ( ! semaphore->recursion_level ) {
463                        semaphore->token_count++;
464                        TRACEF("--rl=%i ++tc=%i",semaphore->recursion_level,semaphore->token_count);
465                        semaphore->current_owner = 0;
466#if 0
467                        if (semaphore->flags & SEM_DELETE_SAFE)
468                                // Task was made deletion-safe when mutex acquired...  Remove deletion safety now.
469                                taskUnsafe();
470#endif
471
472#if USE_PRIORITY_INVERSION
473                        if (semaphore->flags & SEM_INVERSION_SAFE) {
474                                /*
475                                 **  Task priority may have been boosted during
476                                 **  ownership of semaphore...
477                                 **  Restore to original priority now.  Call taskLock
478                                 **  so taskUnlock can be called to restore priority.
479                                 */
480                                TRACEF("Restoring task priority for owner of semaphore list @ %p",
481                                                &(semaphore->first_susp));
482                                taskLock();
483                                taskUnlock();
484                        }
485#endif
486                }
487                // else semaphore->recursion_level > 0
488        } else  {
489                ++semaphore->token_count;
490                TRACEF("++tc=%i",semaphore->token_count);
491        }
492
493#if 1//!FIX_PTHREAD_COND_BUG
494        if (semaphore->first_susp) {
495                pthread_cond_broadcast(&semaphore->sem_send);
496        }
497#endif
498unlock:
499    pthread_mutex_unlock(&semaphore->sem_lock);
500        TRACEF("%x %i %i", (int)semaphore, (int)semaphore->recursion_level, (int)semaphore->token_count);
501exit:
502        {}
503        //pthread_cleanup_pop(0);
504
505        if (error != OK) {
506                errno = (int) error;
507                error = ERROR;
508        }
509        TRACEF("%x",(int)semaphore);
510        return error;
511}
512
513BOOL time_expired(struct timespec *timeout)
514{
515        struct timeval now;
516        gettimeofday(&now, NULL);
517        if (timeout->tv_sec < now.tv_sec)
518                return TRUE;
519        if (timeout->tv_sec > now.tv_sec)
520                return FALSE;
521        assert(timeout->tv_sec == now.tv_sec);
522        return timeout->tv_nsec <= now.tv_usec * 1000;
523}
524
525/*****************************************************************************
526** waiting_on_sem - returns a nonzero result unless a qualifying event
527**                    occurs on the specified semaphore which should cause the
528**                    pended task to be awakened.  The qualifying events
529**                    are:
530**                        1. a token is returned to the semaphore and the
531**                            current task is selected to receive it
532**                        2. the semaphore is deleted or flushed
533*****************************************************************************/
534static int waiting_on_sem(v2lsem_t * semaphore, struct timespec *timeout, int *retcode)
535{
536        int result;
537        TRACEF("%x %i", (int)semaphore, (int)semaphore->token_count);
538        if ((semaphore->send_type & KILLD) || (semaphore->send_type & FLUSH)) {
539                //  Semaphore has been killed... waiting is over.
540                result = 0;
541                *retcode = 0;
542                goto exit;
543        }
544        // Semaphore still in service... check for token availability.
545        //  Initially assume no token available for our task
546        result = 1;
547
548        /*  Multiple posts to the semaphore may be represented by only
549         **  a single signal to the condition variable, so continue
550         **  checking for a token for our task as long as more tokens
551         **  are available. */
552
553        while (semaphore->token_count > 0) {
554                //  Available token arrived... see if it's for our task.
555                if ((signal_for_my_task(&semaphore->first_susp, (semaphore->flags & SEM_Q_PRIORITY)))) {
556                        /**  Token was destined for our task specifically...
557                         **  waiting is over.    */
558                        semaphore->token_count--;
559                        result = 0;
560                        *retcode = 0;
561                        break;
562                } else {
563                        /*
564                         **  Token isn't for our task...  Sleep awhile to
565                         **  allow other tasks ahead of ours in the queue of tasks
566                         **  waiting on the semaphore to get their tokens, bringing
567                         **  our task to the head of the list.
568                         */
569
570                        pthread_mutex_unlock(&(semaphore->sem_lock));
571                        OS_mDelay(10);
572                        pthread_mutex_lock(&(semaphore->sem_lock));
573                }
574
575                if ( timeout && time_expired (timeout))
576                                break;
577        }
578
579exit:
580        return result;
581}
582
583#if USE_PRIORITY_INVERSION
584void priority_inversion(v2lsem_t * semaphore, int max_wait, task_t * our_task)
585{
586        task_t *task;
587        int my_priority, owners_priority, sched_policy;
588        taskLock();
589
590        my_priority = our_task->prv_priority.sched_priority;
591
592        task = semaphore->current_owner;
593        owners_priority = task->prv_priority.sched_priority;
594
595        TRACEF("Task @ %p priority %d owns mutex", task, owners_priority);
596        TRACEF("Calling task @ %p priority %d wants mutex", our_task, my_priority);
597        /*
598         **  If mutex owner's priority is lower than ours, boost it
599         **  to our priority level tempororily until owner releases mutex.
600         **  This avoids 'priority inversion'.
601         */
602        if (owners_priority < my_priority) {
603                struct sched_param schedparam;
604                pthread_attr_getschedpolicy(&task->attr, &sched_policy);
605                pthread_attr_getschedparam(&task->attr, &schedparam);
606                schedparam.sched_priority = my_priority;
607                pthread_attr_setschedparam(&task->attr, &schedparam);
608                pthread_setschedparam(task->pthrid, sched_policy, &schedparam);
609        }
610
611        taskUnlock();
612
613}
614#endif
615
616/*****************************************************************************
617** wait_for_token - blocks the calling task until a token is available on the
618**                  specified v2pthread semaphore.  If a token is acquired and
619**                  the semaphore is a mutex type, this function also handles
620**                  priority inversion and deletion safety issues as needed.
621*****************************************************************************/
622STATUS wait_for_token(v2lsem_t * semaphore, int max_wait, DS_TASK_T * our_task)
623{
624        struct timeval now;
625        struct timespec timeout;
626        int retcode = 0;
627        long sec, usec;
628        STATUS error = OK;
629
630        TRACEF("%x", (int)our_task);
631        link_susp_task(&semaphore->first_susp, our_task);
632
633        if (max_wait == NO_WAIT) {
634                //  Caller specified no wait on semaphore token...
635                //  Check the condition variable with an immediate timeout.
636                gettimeofday(&now, (struct timezone *) NULL);
637                timeout.tv_sec = now.tv_sec;
638                timeout.tv_nsec = now.tv_usec * 1000;
639                while ((waiting_on_sem(semaphore, &timeout, &retcode)) && (retcode != ETIMEDOUT)) {
640                        TRACEF("pthread_cond_timedwait {");
641                        retcode = pthread_cond_timedwait(&semaphore->sem_send, &semaphore->sem_lock, &timeout);
642                        TRACEF("pthread_cond_timedwait }");
643                }
644                if (retcode &&  retcode != ETIMEDOUT) {
645                        error = S_objLib_OBJ_UNAVAILABLE;
646                        TRACEF("...no token available");
647                }
648        } else {
649                //  Caller expects to wait on semaphore, with or without a timeout.
650                //  If the semaphore is a mutex type, check for and handle any
651                //  priority inversion issues.
652#if USE_PRIORITY_INVERSION
653                if ((semaphore->flags & SEM_INVERSION_SAFE) && semaphore->current_owner ) {
654                        priority_inversion(semaphore, max_wait, our_task);
655                }
656#endif
657                if (max_wait == WAIT_FOREVER) {
658                        while (waiting_on_sem(semaphore, 0, &retcode)) {
659                                TRACEF("pthread_cond_timedwait {");
660                                pthread_cond_wait(&semaphore->sem_send, &semaphore->sem_lock);
661                                TRACEF("pthread_cond_timedwait }");
662                        }
663                } else {
664                        /*
665                         **  Wait on semaphore message arrival with timeout...
666                         **  Calculate timeout delay in seconds and microseconds.
667                         */
668                        sec = 0;
669                        usec = max_wait * V2PT_TICK * 1000;
670                        gettimeofday(&now, (struct timezone *) NULL);
671                        usec += now.tv_usec;
672                        if (usec > 1000000) {
673                                sec = usec / 1000000;
674                                usec = usec % 1000000;
675                        }
676                       
677                        timeout.tv_sec = now.tv_sec + sec;
678                        timeout.tv_nsec = usec * 1000;
679
680                        /*
681                         **  Wait for a semaphore message for the current task or
682                         **  for the timeout to expire.  The loop is required since
683                         **  the task may be awakened by signals for semaphore
684                         **  tokens which are not ours, or for signals other than
685                         **  from a semaphore token being returned.
686                         */
687                        while ((waiting_on_sem(semaphore, &timeout, &retcode)) && (retcode != ETIMEDOUT)) {
688#if !FIX_PTHREAD_COND_BUG
689                                TRACEF("pthread_cond_timedwait {");
690                                retcode = pthread_cond_timedwait(&(semaphore->sem_send), &(semaphore->sem_lock), 
691                                    &timeout);
692#endif
693                                TRACEF("pthread_cond_timedwait }");
694           
695                if ( time_expired( &timeout ) )
696                {
697                    retcode = ETIMEDOUT;
698                    break;
699                }
700                else
701                {
702                    retcode = 0;
703                }
704               
705                        pthread_mutex_unlock(&(semaphore->sem_lock));
706                        OS_mDelay(10);
707                        pthread_mutex_lock(&(semaphore->sem_lock));
708                        }
709                }
710                if (retcode == ETIMEDOUT) {
711                        error = S_objLib_OBJ_TIMEOUT;
712                        TRACEF("...timed out");
713                }
714        }
715
716        /*
717         **  Remove the calling task's task from the waiting task list
718         **  for the semaphore.  Clear our TCB's suspend list pointer in
719         **  case the semaphore was killed & its ctrl blk deallocated.
720         */
721        if (our_task) {
722                TRACEF("%x", (int)our_task);
723                unlink_susp_task(&semaphore->first_susp, our_task);
724                //our_task->suspend_list = NULL;
725        }
726
727        //  See if we were awakened due to a semDelete or a semFlush.
728        if ((semaphore->send_type & KILLD) || (semaphore->send_type & FLUSH)) {
729                if (semaphore->send_type & KILLD) {
730                        error = S_objLib_OBJ_ID_ERROR;  // Semaphore deleted
731                        TRACEF("...semaphore deleted");
732                } else {
733                        TRACEF("...semaphore flushed");
734                }
735
736                if ( ! semaphore->first_susp ) {
737                        //pthread_cleanup_push((void (*)(void *)) pthread_mutex_unlock, &semaphore->smdel_lock);
738                        pthread_mutex_lock(&semaphore->smdel_lock);
739                        pthread_cond_broadcast(&semaphore->smdel_cplt);
740                        semaphore->send_type = SEND;
741                        //pthread_cleanup_pop(1);
742                }
743                return error;
744        } 
745
746        if ( retcode == OK) {
747                /*
748                 **  Just received a token from the semaphore...
749                 **  If the semaphore is a mutex, indicate the mutex is now owned
750                 **  by the current task, and then see if the task owning the
751                 **  token is to be made deletion-safe. 
752                 */
753                semaphore->current_owner = our_task->taskId;
754                if ((semaphore->flags & SEM_TYPE_MASK) == MUTEX_SEMA4) {
755                        semaphore->current_owner = our_task->taskId;
756                        semaphore->recursion_level++; // is it a good place?
757#if 0
758                        if (semaphore->flags & SEM_DELETE_SAFE)
759                                taskSafe();
760#endif
761                }
762                TRACEF("OK");
763        }
764
765        return error;
766}
767
768/*****************************************************************************
769** semTake - blocks the calling task until a token is available on the
770**           specified v2pthread semaphore.
771*****************************************************************************/
772STATUS semTake(v2lsem_t * semaphore, int max_wait)
773{
774        DS_TASK_T *our_task;
775        STATUS error = OK;
776        TRACEF();
777        SysASSERT( semaphore );
778       
779        //pthread_cleanup_push((void (*)(void *)) pthread_mutex_unlock, &semaphore->sem_lock);
780        if (!sem_find_lock(semaphore)) {
781                TRACEF("WARNING not found %x ", (int)semaphore);
782                error = S_objLib_OBJ_ID_ERROR;
783                goto exit;
784        }
785       
786        //TRACEF("%i %x %i %i",max_wait, semaphore,semaphore->recursion_level, semaphore->token_count);
787        // If the semaphore is a mutex, check to see if this task already owns the token.
788        our_task = taskFind(0, 1);
789        if ( our_task ) our_task->waiting = (DS_U32 *)semaphore;
790        SysASSERT( our_task );
791       
792        if (((semaphore->flags & SEM_TYPE_MASK) == MUTEX_SEMA4) &&
793                        (semaphore->current_owner == our_task->taskId)) {
794                // TODO: why not just use pthread_mutex_lock with PTHREAD_MUTEX_RECURSIVE mutex ?
795                // because of timeout? -> pthread_cond_timedwait
796
797                //  Current task already owns the mutex...
798                // simply increment the  ownership recursion level and return.
799                semaphore->recursion_level++; // is i a good place?
800                //TRACEF("... recursion level = %d", semaphore->recursion_level);
801        } else {
802                // Either semaphore is not a mutex or current task doesn't own it
803                // Wait for timeout or acquisition of token
804                error = wait_for_token(semaphore, max_wait, our_task);
805        }
806        if ( our_task ) our_task->waiting = (DS_U32 *)NULL;
807        if ( error == OK ) {
808                //++semaphore->recursion_level; // alternate place
809                // TRACEF("++rl  = %i", semaphore->recursion_level);
810        }
811        pthread_mutex_unlock(&(semaphore->sem_lock));
812        TRACEF("%x %i %i", (int)semaphore, (int)semaphore->recursion_level, (int)semaphore->token_count);
813exit:
814        {}
815        //pthread_cleanup_pop(0);
816
817//      if (error != OK) {
818//              errno = (int) error;
819//              error = ERROR;
820//      }
821        return error;
822}
823
Note: See TracBrowser for help on using the repository browser.