source: svn/zas_dstar/hal/os/src/module/lld_sem.c @ 47

Last change on this file since 47 was 47, checked in by megakiss, 11 years ago

459Mhz로 OTC 주파수 변경

File size: 22.3 KB
Line 
1/****************************************************************************
2 * Copyright (c) 2006 DST Technologies Inc.  All Rights Reserved.   
3 *
4 * Module:      SEMS
5 *
6 * Description: This is a decent implementation of semaphores under Linux.
7 *
8 * Notes:   This implementation poses some limitations, some of which can
9 *          be changed by adjusting some defines:
10 *        - Max number of semaphores, shared and local, in the system is
11 *          defined by MAX_NOF_SEMS
12 *        - Max number of processes that can share the same semaphore at
13 *          any given time is defined by MAX_NOF_PROCS
14 *        - When a semaphore is deleted, all tasks within the calling process
15 *          that may be pending on the semaphore will be unlocked with an
16 *          error code.
17 *
18 ***************************************************************************/
19
20/*============================
21 * Includes
22 *===========================*/
23#include "lld_os.h"
24#include "dsthallocal.h"
25#include "lld_local.h"
26#include "os.h"
27
28/*============================
29 * Defines
30 *===========================*/
31#define UNUSED_SEM              0xffffffff
32#define MUTEX_OBJ               0xfffffff0  /* Inidicate a mutex object     */
33#define INVALID_PID             0xffffffff  /* Invalid process ID   */
34#define Semaphore(i)            (SemsPtr->_Sems[i])
35#define SemaphorePtr(i)         (&(SemsPtr->_Sems[i]))
36
37/*============================
38 * Structures
39 *===========================*/
40typedef struct 
41{
42    DS_U32  InitCount;                  /* = UNUSED_SEM if not used         */
43                                        /* = MUTEX_OBJ for mutexes          */
44    DS_U32  Count;                      /* Current count                    */
45    DS_U32  Name;                       /* 0 for local semaphores           */
46    DS_U32  OwnerPid[MAX_NOF_PROCS];    /* Owner process IDs. Contains      */
47                                        /* INVALID_PID for non used entries */
48    DS_U32  LockCount[MAX_NOF_PROCS];   /* Lock count per process           */
49    WAIT_Q  WaitQ;                      /* Queue of processes waiting on    */
50                                        /* the semaphore                    */
51}SEM_STR;
52
53typedef struct
54{
55    SEM_STR _Sems[MAX_NOF_SEMS];
56}SEMS;
57
58/*============================
59 * Shared variables
60 *===========================*/
61static SEMS *SemsPtr = NULL;        /* Pointer to semaphores area */
62
63/*============================
64 * Prototypes
65 *===========================*/
66static DS_U32 SemCreate (DS_U32 SemName, DS_U32 InitCount, DS_U32 *SemId);
67static DS_U32 SemLock (DS_U32 SemId, DS_U32 Timeout, DS_U32 *TimeLeft);
68static DS_U32 SemUnlock (DS_U32 SemId);
69static DS_U32 SemDelete (DS_U32 SemId);
70static DS_U32 SemInfo (DS_U32 SemId, DS_U32 *Size, void *Dest);
71static SEM_STR *GetSemPtr (DS_U32 SemId, DS_U32 *ProcIndex);
72
73#if 0
74 \|/        \|/
75 "@` ______ `@"
76 /  /  ..  \  \
77 --|  \__/  |--
78    \___U__/
79#endif
80
81/*^^***************************************************************************
82 * void SemInit (void)
83 *
84 * Description: Initialize kernel semaphores for first use
85 *
86 * Entry :  None
87 *
88 * Return:  None
89 *
90 * Notes :
91 *
92 **************************************************************************^^*/
93void SemInit (void)
94{
95    DS_U32 i;
96    SEM_STR *SemPtr;
97
98    /*=======================================
99     * Allocate shared mem for semaphores
100     *======================================*/
101    if (SemsPtr == NULL)
102    {
103        SemsPtr = lld_os_malloc (sizeof(SEMS));
104
105        /*=======================================
106         * Initialize semaphors array
107         *======================================*/
108        for (i=0; i<MAX_NOF_SEMS; i++)
109        {
110            SemPtr = SemaphorePtr(i);
111            SemPtr->InitCount = UNUSED_SEM;
112        }
113    }
114}
115
116/*^^***************************************************************************
117 * void SemCleanup (void)
118 *
119 * Description: Cleanup for module shutdown
120 *
121 * Entry :  None
122 *
123 * Return:  None
124 *
125 * Notes :
126 *
127 **************************************************************************^^*/
128void SemCleanup (void)
129{
130    if (SemsPtr != NULL)
131    {
132        lld_os_free (SemsPtr);
133    }
134}
135
136/*^^***************************************************************************
137 * void SemProcessExit (void)
138 *
139 * Description: Cleanup for all semaphores when a process exits normally
140 *              or upnormally. Also unlock all pending tasks/processes.
141 *
142 * Entry :  None
143 *
144 * Return:  None
145 *
146 * Notes :  Any tasks that belong to the terminating process and are pending
147 *          on or already locked the semaphore, will not be notified.
148 *          Pending tasks that belong to other processes will be awakened.
149 *
150 **************************************************************************^^*/
151void SemProcessExit (void)
152{
153    DS_U32  i, j, k, ProcId;
154    DS_BOOL    Removed;
155    SEM_STR *SemPtr;
156
157    ProcId = mCurrentPid;
158
159    /*==============================
160     * For all sems in the system
161     *=============================*/
162    for (i=0; i<MAX_NOF_SEMS; i++)
163    {
164        SemPtr = SemaphorePtr(i);
165        /*===============================
166         * If semaphore exist
167         *==============================*/
168        if (SemPtr->InitCount != UNUSED_SEM)
169        {
170            k = 0;                                  /* Sem reference count */
171            Removed = _FALSE_;
172            /*===============================
173             * Find sem reference count
174             *==============================*/
175            for (j=0; j<MAX_NOF_PROCS; j++)
176            {
177                /*=======================================
178                 * If the terminating proc owns the sem
179                 * remove it from the list
180                 *======================================*/
181                if (SemPtr->OwnerPid[j] == ProcId)
182                {
183                    SemPtr->OwnerPid[j] = INVALID_PID;
184                    Removed = _TRUE_;
185                    /*=================================================
186                     * If sem was locked by this process, unlock it
187                     *================================================*/
188                    if (SemPtr->LockCount[j])
189                    {
190                        if (SemPtr->InitCount == MUTEX_OBJ)
191                        {
192                            SemPtr->Count = 1;
193                        }
194                        else
195                        {
196                            SemPtr->Count += SemPtr->LockCount[j];
197                        }
198                        SemPtr->LockCount[j] = 0;
199                    }
200                }
201                if (SemPtr->OwnerPid[j] != INVALID_PID)
202                {
203                    k++;                            /* Increment ref count */
204                }
205            }
206
207            /*=======================================================
208             * If no other processes reference the sem, delete it
209             *======================================================*/
210            if (k == 0)
211            {
212                SemPtr->InitCount = UNUSED_SEM;
213            }
214            /*============================================
215             * If the process was removed,
216             * Wake up any pending tasks in the system
217             *===========================================*/
218            if (Removed)
219            {
220                lld_wakeup_wait_q (&(SemPtr->WaitQ));
221            }
222        }
223    }
224}
225
226/*^^***************************************************************************
227 * DS_U32 SemOperation (OBJ_OPER *SemPrm)
228 *
229 * Description: Perform semaphore operation defined in SemPrm
230 *
231 * Entry :  SemPrm = Pointer to OBJ_OPER struc holding the requested operation.
232 *
233 * Return:  0 or -ERESTARTSYS
234 *          SemPrm.RetCode hold return values (varies by the opcode)
235 *          SemPrm.Prm2 will also be set as follows:
236 *            Create: SemPrm.Prm2 = Sem ID. = 0 if any error.
237 *            Lock:   SemPrm.Prm2 = Adjusted timeout if ret due to signal
238 *            Info:   SemPrm.Prm2 = Info size
239 *
240 * Notes :
241 *
242 **************************************************************************^^*/
243DS_U32 SemOperation (OBJ_OPER *SemPrm)
244{
245        //printk("b4 SemPrm->Opcode=0x%lX, SemPrm->Prm1=0x%lX, SemPrm->Prm2=0x%lX\n", SemPrm->Opcode, SemPrm->Prm1, SemPrm->Prm2);
246       
247    switch (SemPrm->Opcode)
248    {
249        case OBJ_OPCODE_CREATE:
250            SemPrm->RetCode = SemCreate (SemPrm->Prm1, SemPrm->Prm2, 
251                                         &(SemPrm->Prm2));
252            break;
253        case OBJ_OPCODE_DELETE:
254            SemPrm->RetCode = SemDelete (SemPrm->Prm1);
255            break;
256        case OBJ_OPCODE_LOCK:
257            SemPrm->RetCode = SemLock (SemPrm->Prm1, SemPrm->Prm2, 
258                                       &(SemPrm->Prm2));
259            if (SemPrm->RetCode == OBJ_SIGNAL_RCV)
260            {
261                return (ERR_RESTART_SYS);
262            }
263            break;
264        case OBJ_OPCODE_UNLOCK:
265            SemPrm->RetCode = SemUnlock (SemPrm->Prm1);
266            break;
267        case OBJ_OPCODE_INFO:
268            SemPrm->RetCode = SemInfo (SemPrm->Prm1, &(SemPrm->Prm2), 
269                                       (void *)(SemPrm->Prm2));
270            break;
271        default:
272            SemPrm->RetCode = OBJ_INVALID_OP;
273            break;
274    }
275        //printk("a4 SemPrm->Opcode=0x%lX, SemPrm->Prm1=0x%lX, SemPrm->Prm2=0x%lX\n", SemPrm->Opcode, SemPrm->Prm1, SemPrm->Prm2);
276
277    return (0);
278}
279
280/*^^***************************************************************************
281 * static DS_U32 SemCreate (DS_U32 SemName, DS_U32 InitCount, DS_U32 *SemId)
282 *
283 * Description: Creates a semaphore object with the specified count.
284 *
285 * Entry :  SemName     = Unique number identifying the semaphore.
286 *                        Set to NULL to create unnamed semaphore (can not be
287 *                        used for inter-process synchronization)
288 *          InitCount   = Initial semaphore count (0 to 255)
289 *                        or MUTEX_OBJ for a mutex
290 *          SemId       = Pointer to receive semaphore ID
291 *
292 * Return:  Entry SemId holds semaphore ID. =0 if any error. Return codes are:
293 *          OBJ_OK              Operation completed
294 *          OBJ_INVALID_ID      Invalid sem id or process does not own sem
295 *          OBJ_MAX_PROCS       Max number of procs reached
296 *          OBJ_MAX_OBJS        Max number of semaphores reached
297 *          OBJ_COUNT_MISMATCH  Shared sem init count does not match
298 *
299 * Notes :  If the same process creates a shared semaphore multiple times,
300 *          it's pid will appear in the semaphore's OwnerPid list only once.
301 *          In this case, only one delete is required by the calling process
302 *          to delete the semaphore.
303 *
304 **************************************************************************^^*/
305static DS_U32 SemCreate (DS_U32 SemName, DS_U32 InitCount, DS_U32 *SemId)
306{
307    DS_U32 i, j;
308    SEM_STR *SemPtr = NULL;
309
310    *SemId = 0;
311    if (((InitCount > 255) && (InitCount != MUTEX_OBJ)) || (SemsPtr == NULL))
312    {
313        return (OBJ_INVALID_ID);
314    }
315
316    /*================================
317     * If shared semaphore
318     *===============================*/
319    if (SemName != 0)
320    {
321        /*===========================================
322         * Find if shared sem exist (same name)
323         *==========================================*/
324        for (i=0; i<MAX_NOF_SEMS; i++)
325        {
326            SemPtr = SemaphorePtr(i);
327            if ((SemPtr->InitCount != UNUSED_SEM) && (SemPtr->Name == SemName))
328            {
329                if (SemPtr->InitCount != InitCount)
330                {
331                    return (OBJ_COUNT_MISMATCH);
332                }
333                /*===============================================
334                 * Find if current process already owns the sem
335                 *==============================================*/
336                for (j=0; j<MAX_NOF_PROCS; j++)
337                {
338                    if (SemPtr->OwnerPid[j] == mCurrentPid)
339                    {
340                        *SemId = (i+1);
341                        return (OBJ_OK);
342                    }
343                }
344                /*===============================================
345                 * No, add process to owners list
346                 *==============================================*/
347                for (j=0; j<MAX_NOF_PROCS; j++)
348                {
349                    if (SemPtr->OwnerPid[j] == INVALID_PID)
350                    {
351                        SemPtr->OwnerPid[j] = mCurrentPid;
352                        SemPtr->LockCount[j] = 0;
353                        *SemId = (i+1);
354                        return (OBJ_OK);
355                    }
356                }
357                return (OBJ_MAX_PROCS);
358            }
359        }
360    }
361
362    /*======================================================
363     * If sem does not exist or local sem, create new one
364     *=====================================================*/
365    for (i=0; i<MAX_NOF_SEMS; i++)
366    {
367        SemPtr = SemaphorePtr(i);
368        if (SemPtr->InitCount == UNUSED_SEM)
369        {
370            SemPtr->InitCount = InitCount;
371            SemPtr->Count = InitCount;
372            if (InitCount == MUTEX_OBJ)
373            {
374                SemPtr->Count = 1;
375            }
376            SemPtr->Name = SemName;
377            for (j=0; j<MAX_NOF_PROCS; j++)
378            {
379                SemPtr->OwnerPid[j] = INVALID_PID;
380            }
381            SemPtr->OwnerPid[0] = mCurrentPid;
382            SemPtr->LockCount[0] = 0;
383            lld_init_wait_q (&(SemPtr->WaitQ));
384            *SemId = (i+1);
385            return (OBJ_OK);
386        }
387    }
388    return (OBJ_MAX_OBJS);
389}
390
391/*^^***************************************************************************
392 * static DS_U32 SemLock (DS_U32 SemId, DS_U32 Timeout, DS_U32 *TimeLeft)
393 *
394 * Description: Locks a semaphore (decrement count) with a timeout
395 *
396 * Entry :  SemId    = Returned by SemCreate
397 *          Timeout  = In 1/100 of a second increments.
398 *                     = 0 to return immidiately if the resource not available
399 *                     = 0xffffffff to wait forever on the resource
400 *          TimeLeft = Pointer to DS_U32 to receive remaining timeout if the
401 *                     lock operation interrupted by a signal (if return value
402 *                     is OBJ_SIGNAL_RCV)
403 *
404 * Return:  OBJ_OK              Operation completed
405 *          OBJ_INVALID_ID      Invalid sem id or process does not own sem
406 *          OBJ_TIMEOUT         Timedout
407 *          OBJ_SIGNAL_RCV      Signal received
408 *
409 * Notes :  If sem count > 0, it will be decremented and the function will
410 *          return 0
411 *          If sem count = 0 and Timeout = 0, the function will return timeout
412 *          If sem count = 0 and Timeout > 0, other processes will be
413 *          scheduled until either timeout is elapsed (return TIMEOUT), the
414 *          calling process detects that sem count > 0 (return OK) or the
415 *          process receives a signal (return SIGNAL_RCV)
416 *         
417 *          **** VERY IMPORTANT ***
418 *          This locking mechanism does not support priority inversion since
419 *          linux does not support (_TRUE_) task priorities.
420 *
421 **************************************************************************^^*/
422static DS_U32 SemLock (DS_U32 SemId, DS_U32 Timeout, DS_U32 *TimeLeft)
423{
424    DS_U32 i, Idx;
425    SEM_STR *SemPtr;
426
427    while (_TRUE_)
428    {
429        /*===========================================
430         * Make sure sem still exist (not deleted)
431         *==========================================*/
432        SemPtr = GetSemPtr(SemId, &Idx);
433        if (SemPtr == NULL)
434        {
435            return (OBJ_INVALID_ID);
436        }
437
438        /*==========================
439         * If Count > 0
440         *=========================*/
441        if (SemPtr->Count != 0)
442        {
443            SemPtr->Count--;
444            SemPtr->LockCount[Idx]++;
445            return (OBJ_OK);
446        }
447
448        /*================================
449         * If Count == 0 and no timeout
450         *===============================*/
451        if (Timeout == 0)
452        {
453            return (OBJ_TIMEOUT);
454        }
455
456        /*===========================================================
457         * If Count == 0 and timeout, wait unlock or timeout event
458         *==========================================================*/
459        if (Timeout == OS_WAIT_FOREVER)
460        {
461            lld_wait_on_q (&(SemPtr->WaitQ));
462            i = Timeout;                        /* Any non zero value */
463        }
464        else
465        {
466            i = lld_timeout_wait_on_q(&(SemPtr->WaitQ), Timeout);
467        }
468        if (i == 0)
469        {
470            return (OBJ_TIMEOUT);
471        }
472        if (lld_os_signal_detected())
473        {
474            *TimeLeft = i;
475            return (OBJ_SIGNAL_RCV);
476        }
477        if (Timeout != OS_WAIT_FOREVER)
478        {
479            Timeout = i;
480        }
481    }
482}
483
484/*^^***************************************************************************
485 * static DS_U32 SemUnlock (DS_U32 SemId)
486 *
487 * Description: Unlock a semaphore (Increment count)
488 *
489 * Entry :  SemId   = Returned by SemCreate
490 *
491 * Return:  OBJ_OK              Operation completed
492 *          OBJ_INVALID_ID      Invalid sem id or process does not own sem
493 *          OBJ_BAD_COUNT       Bad count
494 *
495 * Notes:   The semaphore count will be incremented even if it is > creation
496 *          time initial count. First scheduled pending task will be awakended
497 *          to lock the semaphore.
498 *
499 **************************************************************************^^*/
500static DS_U32 SemUnlock (DS_U32 SemId)
501{
502    DS_U32 Idx;
503    SEM_STR *SemPtr;
504
505    SemPtr = GetSemPtr(SemId, &Idx);
506    if (SemPtr == NULL)
507    {
508        return (OBJ_INVALID_ID);
509    }
510    if ((SemPtr->InitCount == MUTEX_OBJ) && (SemPtr->Count == 1))
511    {
512        return (OBJ_OK);
513    }
514    SemPtr->Count++;
515    /*==============================================================
516     * Decrease lock count only if sem was locked by this process
517     *=============================================================*/
518    if (SemPtr->LockCount[Idx])
519    {
520        SemPtr->LockCount[Idx]--;
521    }
522    lld_wakeup_wait_q (&(SemPtr->WaitQ));
523    return (OBJ_OK);
524}
525
526/*^^***************************************************************************
527 * static DS_U32 SemDelete (DS_U32 SemId)
528 *
529 * Description: Deletes a semaphore.
530 *
531 * Entry :  SemId   = Returned by SemCreate
532 *
533 * Return:  OBJ_OK              Operation completed
534 *          OBJ_INVALID_ID      Invalid sem id or process does not own sem
535 *
536 * Notes:   The semaphore will be deleted only if its reference count is 0.
537 *          All tasks waiting on the semaphore will be unblocked with error
538 *          return code. Tasks that already locked the semaphore will get
539 *          an error the next time they perform any semaphore operation.
540 *          The only caveat here is:
541 *          If a taskA deletes a semaphore while other task(s) are pending or
542 *          already locked it, and TaskA then creates another semaphore before
543 *          the other tasks gets notified of the deleted semaphore, it is
544 *          possible that the returned SemId will be the same as the just
545 *          deleted semaphore and hence other pending/locked task(s) will
546 *          continue to run normally.
547 *
548 **************************************************************************^^*/
549static DS_U32 SemDelete (DS_U32 SemId)
550{
551    DS_U32 i, j;
552    SEM_STR *SemPtr;
553
554    SemPtr = GetSemPtr(SemId, &j);
555    if (SemPtr == NULL)
556    {
557        return (OBJ_INVALID_ID);
558    }
559
560    /*======================================
561     * Remove process from owners list
562     *=====================================*/
563    SemPtr->OwnerPid[j] = INVALID_PID;
564
565    /*==================================================
566     * Check if other process still use the semaphore
567     *=================================================*/
568    j = 0;
569    for (i=0; i<MAX_NOF_PROCS; i++)
570    {
571        if (SemPtr->OwnerPid[i] != INVALID_PID)
572        {
573            j = 1;                          /* Other process is using it */
574            break;
575        }
576    }
577
578    /*================================================
579     * If no other process is using the semaphore
580     *===============================================*/
581    if (j == 0)
582    {
583        SemPtr->InitCount = UNUSED_SEM;
584    }
585
586    /*======================================
587     * Awake all tasks waiting on the sem
588     *=====================================*/
589    lld_wakeup_wait_q (&(SemPtr->WaitQ));
590    return (OBJ_OK);
591}
592
593/*^^***************************************************************************
594 * static void SemInfo (DS_U32 SemIdx, DS_U32 *Size, void *Dest)
595 *
596 * Description: Return a copy of kernel structure for a semaphore.
597 *
598 * Entry :  SemId   = User mode sem ID
599 *          Size    = Pointer to receive size of sem structure
600 *          Dest    = Area to copy sem info to
601 *
602 * Return: 
603 *
604 * Notes:   This fucntion is provided for diagnostic purpose only.
605 *
606 **************************************************************************^^*/
607static DS_U32 SemInfo (DS_U32 SemId, DS_U32 *Size, void *Dest)
608{
609    SEM_STR *SemPtr;
610
611    SemId--;
612    if ((SemId >= MAX_NOF_SEMS) || (SemsPtr == NULL))
613    {
614        return (OBJ_INVALID_ID);
615    }
616    SemPtr = SemaphorePtr(SemId);
617    *Size = sizeof (SEM_STR);
618    lld_os_copy_to_user(Dest, (DS_S8 *)SemPtr, sizeof(SEM_STR));
619    return (OBJ_OK);
620}
621
622/*^^***************************************************************************
623 * static SEM_STR *GetSemPtr (DS_U32 SemId, DS_U32 *ProcIndex)
624 *
625 * Description: Find semaphore corresponding to a sem ID and process ID
626 *
627 * Entry :  SemId       = User mode sem ID
628 *          ProcIndex   = Ptr to receive process index in OwnerPid array or
629 *                        NULL if not needed
630 *
631 * Return:  Pointer to semaphore struc or NULL
632 *
633 * Notes:   This call will fail if the semaphore does not exist or if
634 *          the caller process did not create the semaphore.
635 *
636 **************************************************************************^^*/
637static SEM_STR *GetSemPtr (DS_U32 SemId, DS_U32 *ProcIndex)
638{
639    SEM_STR *SemPtr;
640    DS_U32  i, ProcId;
641
642    SemId--;
643    if ((SemId >= MAX_NOF_SEMS) || (SemsPtr == NULL))
644    {
645        return (NULL);
646    }
647    ProcId = mCurrentPid;                  /* Current process ID */
648    SemPtr = SemaphorePtr(SemId);
649    if (SemPtr->InitCount == UNUSED_SEM)
650    {
651        return (NULL);
652    }
653    for (i=0; i<MAX_NOF_PROCS; i++)
654    {
655        if (SemPtr->OwnerPid[i] == ProcId)
656        {
657            if (ProcIndex != NULL)
658            {
659                *ProcIndex = i;
660            }
661            return (SemPtr);
662        }
663    }
664    return (NULL);
665}
Note: See TracBrowser for help on using the repository browser.