/******************************************************************** DHL_OSAL.c PHOENIX Driver HAL library OS Abstraction Layer implementation Copyright 2006 Digital STREAM Technology, Inc. All Rights Reserved $Id: DHL_OSAL.c v1.00 2006/04 cafrii Exp $ ********************************************************************/ /* Include files */ #include "DHL_Types.h" #include "DHL_OSAL.h" #include "DHL_OSAL_Impl.h" #include "DHL_DBG.h" #include "bcm_mips_defs.h" #include "bcm_mips.h" #include "bcmmemmgr.h" #include "bos.h" /* define */ #define USE_BCM_MUTEX 0 #define USE_BCM_MSG_QUEUE 0 #if USE_BCM_MUTEX #include "bkni.h" #include "bkni_multi.h" #endif #if USE_BCM_MSG_QUEUE #include "bos.h" #endif // to enable verbose debug message. #define OSAL_DEBUG 0 // to use message queue in ISR, we should not use mutex. // remove codes after verification. // #define BUGFIX_MSGQ 1 #define max(a,b) (((a) > (b)) ? (a) : (b)) #define min(a,b) (((a) < (b)) ? (a) : (b)) #if COMMENT _______________(){} #endif void dhl_dbg_flush_console(void) { //BKTEMP console_flush(); } int osi_dbgprint(char *fmt, ...) { // DMC ¿¡¼­ »ç¿ëÇÏ´Â debug print. char msgPrefix[50]; va_list v; int n; char buf[200]; dhl_dbg_flush_console(); //if (g_Trace_EpgBase <= nLevel) return 0; snprintf(msgPrefix, 200, "[osi %s %d] ", DHL_OS_TaskName(0), DHL_OS_TaskPriority()); va_start(v, fmt); n = BKNI_Vsnprintf(buf, 200, fmt, v); va_end(v); BKNI_Printf(msgPrefix); BKNI_Printf(buf); dhl_dbg_flush_console(); return n; } #undef printf #define printf osi_dbgprint #if COMMENT ___Internal_alloc___(){} #endif /* this is only for osal_impl internal. do not use this outside. */ static void *osi_calloc(int n) { void *p; #ifdef BCM_DEBUG p = malloc_align_dbg(n, 2, __FILE__, __LINE__); #else p = OS_Malloc(n); #endif memset(p, 0, n); return p; } static void osi_free(void *p) { // p is not compatible with OS_Free. // this will not reset pointer. #ifdef BCM_DEBUG free_dbg(p, __FILE__, __LINE__); #else OS_FreeDirect(p); #endif } #if COMMENT ___Tick_Func___(){} #endif UINT32 osi_gettickcount() { return bos_getticks(); } UINT32 osi_gettickspersecond() { return g_ticks_per_second; } void osi_delay(UINT32 millisec) { bos_sleep(millisec); } #if COMMENT ___Task_related_Func___(){} #endif extern unsigned char OSIntNesting; BOOL osi_in_interrupt(void) { return OSIntNesting > 0 ? TRUE : FALSE; } /* interrupt disable/enable: */ UINT32 osi_disableint() { /* ´Ü¼øÈ÷ OS_ENTER_CRITICAL ¸¸ Çϸé ÃæºÐÇÏÁö ¾Ê´Ù. int disable ÇØµµ OS scheduleÀÌ µÇ±âµµ Çϴµ¥, »õ·Î¿î task¿¡¼­ÀÇ cp0:$12ÀÇ int°¡ enable µÇ¾î ÀÖ´Ù¸é ¾Æ¹« Àǹ̰¡ ¾ø¾îÁø´Ù. »ç½Ç OSSched() ³»ºÎ¿¡¼­µµ OS_ENTER_CRITICAL µÈ »óÅ¿¡¼­ switching ÇÑ´Ù. °á·ÐÀº ¿Ïº®ÇÏ°Ô int disable ÇÏ·Á¸é schedulerµµ °°ÀÌ disable ½ÃÄÑ¾ß ÇÑ´Ù. */ UINT32 flags; OSSchedLock(); flags = MIPS_SetInterrupts(OS_DISABLE); // OS_ENTER_CRITICAL(flags); return flags; } void osi_enableint(UINT32 mask) { MIPS_SetInterrupts(mask);// OS_EXIT_CRITICAL(mask); OSSchedUnlock(); } extern unsigned char OSLockNesting; BOOL osi_in_tasklock(void) { return OSLockNesting> 0 ? TRUE : FALSE; } /* lock/unlock task: disable/enable OS scheduler. */ UINT32 osi_locktask() { OSSchedLock(); // actually, return value is not important.. return OSLockNesting; } void osi_unlocktask(UINT32 mask) { //mask is unused. OSSchedUnlock(); } char *osi_taskname(os_task_id tid) { b_task_stats *stat=bos_get_task_info((b_task_t)tid); if(stat) return stat->name; return NULL; } /* note! OSTCBCur should be accessed with all interrupt disabled. */ int osi_taskpriority() { int prio; UINT32 flags; flags = MIPS_SetInterrupts(OS_DISABLE); // OS_ENTER_CRITICAL(flags); prio = (int)OSTCBCur->OSTCBPrio; MIPS_SetInterrupts(flags);// OS_EXIT_CRITICAL(flag); return prio; } os_task_id osi_taskid() { #if 0//#ifdef UCOS_II os_task_id id; OS_TCB tcb; OSTaskQuery( OS_PRIO_SELF, &tcb ); /* use our priority as a task id */ id = tcb.OSTCBPrio;; #else os_task_id id; UINT32 flags; flags = MIPS_SetInterrupts(OS_DISABLE); // OS_ENTER_CRITICAL(flags); id = OSTCBCur->OSTCBPrio; MIPS_SetInterrupts(flags);// OS_EXIT_CRITICAL(flag); #endif return id; } os_task_id osi_taskidfromname(char *tname) { int i; b_task_stats *stat=NULL; for(i=0, stat=bos_get_task_info(i); stat; i++) { if(0==strcmp(stat->name, tname)) return (os_task_id)i; stat=bos_get_task_info(i); } return 63; } void osi_changetaskpriority(os_task_id tid, UINT32 newPrio, UINT32 *oldPrioPtr) { if(tid==0) { tid=osi_taskpriority(); } OSTaskChangePrio(tid, newPrio); *oldPrioPtr = tid; } void osi_selfdeletetask(void) { OSTaskDel(OS_PRIO_SELF); } void osi_deletetask(os_task_id tid) { bos_stop_task((b_task_t)tid); } #if 0 static void osi_taskbody(int *osparam) { os_taskfunction func = (os_taskfunction)(osparam[0]); void *arg = (void *)(osparam[1]); #if 1 // cafrii 081014 add. // turn on IE bit for normal operation. // it is possible that parent task call OS_SpawnTask in IE disabled state. // in such case, child task start as IE disabled state, which is abnormal. // unsigned long status; status = bcm_read_cp0($12,0); status |= ST0_IE; bcm_write_cp0($12,0, status); #endif (*func)(arg); while (1) { // wait forever.. DHL_OS_Delay(DHL_OS_GetTicksPerSecond()*60*60); }; } #endif /* in DST OSAL api, stackSize is byte size. in osi_show_taskinfo(), the stack size is word (4-byte) unit. we provide stub function to call real user task function. if user task function completes, it waits forever. os_task_id is its priority! (NOTICE: inversion value) */ os_task_id osi_spawntask(os_taskfunction func, const char *name, int priority, UINT32 stackSize, UINT32 arg1) { b_task_t tid; b_task_params param; unsigned int *p; int stk_size_word = (stackSize + 3)/4; // round up. (align) #if 0 /* cafrii 081014 add check code: in uCOS, parent task has IE disabled, child (created) task also run in IE disabled state. OS_LockTask() makes IE disabled. So, we should not call OS_SpawnTask() after OS_LockTask(). */ if (OS_IS_ISR()) { printf("\n!! spawn task in privileged level\n"); printf("SR: %08x\n", bcm_read_cp0($12,0)); stack_backtrace(0, 0, 0, 0); } #endif param.priority=priority; param.stack_size=stk_size_word; p = (unsigned int *) osi_calloc(stk_size_word*sizeof(int) + sizeof(int)*2); param.stack = p; param.name = name; #if 0//ndef UCOS_II //ucOS p = p + stk_size_word; // we place osparam at the end of mem block. (== bottom of stack) p[0] = (unsigned int) func; p[1] = (unsigned int) arg1; #endif //BKTEMP if(b_ok!=bos_start_task(&tid, ¶m, (b_task_func)osi_taskbody, (void *)p)) { if(b_ok!=bos_start_task(&tid, ¶m, func, (void *)arg1)) { printf("!! err : fail to create task\n"); return 0; } return (os_task_id)tid; } #if COMMENT ___Sem_related_Func___(){} #endif #define SIZE_SEM_NAME 15 enum { SEM_MUTEX=0x1, SEM_BINARY=0X2, SEM_COUNTING=0X3, SEM_MSGQ=0x4, }; typedef struct { UINT8 type; // UINT32 handler; OS_EVENT* handler; #if USE_BCM_MUTEX BKNI_MutexHandle hMutex; #endif char name[SIZE_SEM_NAME+1]; //--------- UINT8 nRecursive; UINT32 owner; //mutex void *next; // for free list managent of reuse semaphore. } SemType; #if OSAL_DEBUG int g_os_sem_create_count; #define trace_sem_create(type) \ printf("==== sem create: " #type " %d, os-free %d, dhl-free %d\n", \ ++g_os_sem_create_count, OSSemGetFreeCount(), osi_free_reuse_sem_count()) #else #define trace_sem_create(type) #endif /* ucos semaphore wrapper take -> SemAccept/SemPend give -> SemPost */ static DHL_RESULT _takesemaphore(SemType *sem, int ticks) { DHL_RESULT result=DHL_OK; UINT8 err; #if OSAL_DEBUG if (sem->type != SEM_MUTEX) { printf("#### take %c sem '%s' %x, h %x, tick %d\n", sem->type == SEM_BINARY ? 'b' : sem->type == SEM_MUTEX ? 'm' : 'c', sem->name, sem, sem->handler, ticks); } #endif #if 0 if (OS_IS_ISR() && ticks != NO_WAIT) return DHL_FAIL_INVALID_STATE; #endif if (ticks == NO_WAIT) { INT16U value= OSSemAccept((OS_EVENT *)sem->handler); // printf("sem_count: %d/%d\n",value, sem->handler->OSEventCnt); if (value > 0) result = DHL_OK; else result = DHL_FAIL_TIMEOUT; } else if (ticks == WAIT_FOREVER) { do { OSSemPend((OS_EVENT *)sem->handler, 0xffff, &err); } while (err == OS_TIMEOUT); if(err!=OS_NO_ERR) { printf("ERR: _takesemaphore %d\n", err); result=DHL_FAIL_TIMEOUT; }else result = DHL_OK; } else // unlimited tick range. { // repeat until ticks are all consumed or err occurred. UINT32 prev, cur, ticks_left = ticks; UINT32 rounds = 0; // for debugging. cur = osi_gettickcount(); do { prev = cur; rounds++; OSSemPend((OS_EVENT *)sem->handler, min(0xffff, ticks_left), &err); if (err == OS_TIMEOUT) { // we should do more rounds until all 'ticks' consumed. cur = osi_gettickcount(); if(cur >= prev) ticks_left -= (cur - prev); // decrease tick by elapsed time. else ticks_left -= (cur + prev); } } while (err == OS_TIMEOUT && ticks_left > 0); // if(OS_NO_ERR != err) // { // printf("!!!! OSSemPend err=%d\n",err); // } #if OSAL_DEBUG if (rounds > 1) { printf("!!!! semtype %d: total %d rounds, requested ticks: %d (0x%x)\n", sem->type, rounds, ticks); } #endif if(err!=OS_NO_ERR) { // printf("ERR: _takesemaphore %d\n", err); result=DHL_FAIL_TIMEOUT; }else result = DHL_OK; } return result; } static void _givesemaphore(SemType *sem) { #if OSAL_DEBUG if (sem->type != SEM_MUTEX) { printf("#### give %c sem %s %x, h %x\n", sem->type == SEM_BINARY ? 'b' : sem->type == SEM_MUTEX ? 'm' : 'c', sem->name, sem, sem->handler); } #endif #if 0//BKTODO: semaphore, mutexÀÎ °æ¿ì °í·Á ÇÊ¿äÇÔ. (ucOS-II¿¡´Â OSSemPostEx()°¡ Á¦°øµÇÁö ¾Ê´Â´Ù.) if (sem->type == SEM_BINARY || sem->type == SEM_MUTEX) OSSemPostEx((OS_EVENT *)sem->handler, 1); // return value 'OS_SEM_OVF' is not error. else OSSemPost((OS_EVENT *)sem->handler); #else #if 1//BK - binary semaphore acts like counting semaphore if(sem->type == SEM_BINARY) { if(sem->handler->OSEventCnt > 0) { printf("skip: bin sema4 cnt=%d\n", sem->handler->OSEventCnt ); return; } } #endif OSSemPost((OS_EVENT *)sem->handler); #endif } int osi_takesemaphore(os_semaphore_id sid) { return osi_takesemaphore_wait(sid, WAIT_FOREVER); } int osi_takesemaphore_wait(os_semaphore_id sid, int ticks) { DHL_RESULT result=DHL_OK; SemType *sem=(SemType *)sid; if(sem->type == SEM_MUTEX) { return osi_takemutexsemaphore_wait(sid, ticks); } result = _takesemaphore(sem, ticks); return result; } int osi_takesemaphore_nowait(os_semaphore_id sid) { return osi_takesemaphore_wait(sid, NO_WAIT); } int osi_givesemaphore(os_semaphore_id sid) { DHL_RESULT result; SemType *sem=(SemType *)sid; if(sem->type==SEM_MUTEX) { osi_givemutexsemaphore(sid); return DHL_OK; } _givesemaphore(sem); result = DHL_OK; return result; } int osi_flushsemaphore(os_semaphore_id sid) { SemType *sem=(SemType *)sid; if(sem->type == SEM_MUTEX) { printf("!! %s: error, sem is mutex\n", __FUNCTION__); return DHL_FAIL_INVALID_PARAM; } while(OSSemAccept((OS_EVENT *)sem->handler)>0); return DHL_OK; } void osi_deletesemaphore(os_semaphore_id sid) { // printf("!! %s: delete sem not supported!!\n", __FUNCTION__); INT8U err; SemType *sem=(SemType *)sid; if(sem) { #if USE_BCM_MUTEX if(sem->type == SEM_MUTEX) { BKNI_DestroyMutex(sem->hMutex); osi_free(sem); return; }else #endif { OSSemDel((OS_EVENT *)sem->handler, OS_DEL_ALWAYS, &err);//BKTODO: option°ª È®ÀοäÇÔ. OS_DEL_NO_PEND -> OS_DEL_ALWAYS osi_free(sem); return; } } } #if COMMENT _______(){} #endif int osi_takemutexsemaphore_wait(os_semaphore_id sid, int ticks) { #if USE_BCM_MUTEX SemType *sem=(SemType *)sid; UINT32 flags; DHL_RESULT result; BERR_Code err; if (sem->type != SEM_MUTEX) { printf("!! %s: error, sem is NOT a mutex\n", __FUNCTION__); return DHL_FAIL_INVALID_PARAM; } if (ticks == NO_WAIT) { err = BKNI_TryAcquireMutex(sem->hMutex); if(err==BERR_SUCCESS) { result = DHL_OK; }else { printf("ERR: _takesemaphore %d\n", err); result=DHL_FAIL_TIMEOUT; } } else if (ticks == WAIT_FOREVER) { err = BKNI_AcquireMutex(sem->hMutex); if(err==BERR_SUCCESS) { result = DHL_OK; }else { printf("ERR: _takesemaphore %d\n", err); result=DHL_FAIL_TIMEOUT; } } else // unlimited tick range. { int prev, cur, ticks_left = ticks; int rounds = 0; // for debugging. cur = osi_gettickcount(); do { prev = cur; rounds++; err = BKNI_AcquireMutexTimeout(sem->hMutex, ticks_left); if (err != BERR_SUCCESS) { // we should do more rounds until all 'ticks' consumed. ticks_left -= ((cur = osi_gettickcount()) - prev); // decrease tick by elapsed time. } } while (err == BERR_SUCCESS && ticks_left > 0); if(err!=BERR_SUCCESS) { printf("ERR: _takesemaphore %d\n", err); result=DHL_FAIL_TIMEOUT; }else { result = DHL_OK; } } if(result == DHL_OK) { flags = MIPS_SetInterrupts(OS_DISABLE); // OS_ENTER_CRITICAL(flags); sem->owner = (UINT32)OSTCBCur->OSTCBPrio; MIPS_SetInterrupts(flags);// OS_EXIT_CRITICAL(flags); } #else SemType *sem=(SemType *)sid; UINT32 flags; DHL_RESULT result; if (sem->type != SEM_MUTEX) { printf("!! %s: error, sem is NOT a mutex\n", __FUNCTION__); return DHL_FAIL_INVALID_PARAM; } #if 0 // ISR ³»ºÎÀÎÁö, critical section ¾ÈÀÎÁö ±¸ºÐÇÒ ¼ö ¾øÀ½. if (OS_IS_ISR() && ticks != NO_WAIT) { printf("!! %s: mutex in ISR! '%s'\n", __FUNCTION__, sem->name); return DHL_FAIL_INVALID_STATE; } #endif flags = MIPS_SetInterrupts(OS_DISABLE); // OS_ENTER_CRITICAL(flags); // check if this mutex is already ours. if (sem->owner == (UINT32)OSTCBCur->OSTCBPrio) { //osi_taskid()=>OSTCBCur->OSTCBPrio // this task already owns this mutex. sem->nRecursive++; MIPS_SetInterrupts(flags);// OS_EXIT_CRITICAL(flags); result = DHL_OK; } else { // its not ours. so, this mutex is similar to normal semaphores. // try to take.. MIPS_SetInterrupts(flags);// OS_EXIT_CRITICAL(flags); result = _takesemaphore(sem, ticks); if (result == DHL_OK) { flags = MIPS_SetInterrupts(OS_DISABLE); // OS_ENTER_CRITICAL(flags); sem->owner = (UINT32)OSTCBCur->OSTCBPrio; sem->nRecursive = 0; MIPS_SetInterrupts(flags);// OS_EXIT_CRITICAL(flags); } } #endif return result; } /* unlock mutex. */ void osi_givemutexsemaphore(os_semaphore_id sid) { #if USE_BCM_MUTEX SemType *sem=(SemType *)sid; UINT32 flags; UINT32 tid; if(sem->type != SEM_MUTEX) { printf("!! %s: error, sem is NOT a mutex\n", __FUNCTION__); return; } flags = MIPS_SetInterrupts(OS_DISABLE); // OS_ENTER_CRITICAL(flags); if (sem->owner == OSTCBCur->OSTCBPrio) {//osi_taskid()=>OSTCBCur->OSTCBPrio MIPS_SetInterrupts(flags);// OS_EXIT_CRITICAL(flags); BKNI_ReleaseMutex(sem->hMutex); }else { MIPS_SetInterrupts(flags);// OS_EXIT_CRITICAL(flags); printf("!! %s: try unlock mutex (0x%x '%s') of others (tid %d)\n", __FUNCTION__, sem, sem->name, sem->owner); } #else SemType *sem=(SemType *)sid; UINT32 flags; if(sem->type != SEM_MUTEX) { printf("!! %s: error, sem is NOT a mutex\n", __FUNCTION__); return; } flags = MIPS_SetInterrupts(OS_DISABLE); // OS_ENTER_CRITICAL(flags); if (sem->owner == OSTCBCur->OSTCBPrio) {//osi_taskid()=>OSTCBCur->OSTCBPrio // this mutex is owned by me! if (sem->nRecursive > 0) { sem->nRecursive--; MIPS_SetInterrupts(flags);// OS_EXIT_CRITICAL(flags); } else { if(sem->owner) { // this is the last 'give'. sem->owner = 0; MIPS_SetInterrupts(flags);// OS_EXIT_CRITICAL(flags); // no body can 'give' this mutex. // so i can safely exit critical. _givesemaphore(sem); }else { printf("err: mutex no ownership\n"); } } } else { MIPS_SetInterrupts(flags);// OS_EXIT_CRITICAL(flags); printf("!! %s: try unlock mutex (0x%x '%s') of others (tid %d)\n", __FUNCTION__, sem, sem->name, sem->owner); } #endif } #if COMMENT _______(){} #endif os_semaphore_id osi_createcountingsemaphore(const char *name, UINT32 options, UINT32 count) { SemType *sem; sem=(SemType *)osi_calloc(sizeof(SemType)); if (sem==NULL) { return 0; } if (count > 65535) count = 65535; strncpy(sem->name, name, SIZE_SEM_NAME-1); sem->type=SEM_COUNTING; sem->nRecursive=0; sem->owner=0; sem->handler=(OS_EVENT*)OSSemCreate(count); if (sem->handler == 0) { osi_free(sem); return 0; } // OSSaveUserData((OS_EVENT *)sem->handler, sem); trace_sem_create(count); return (os_semaphore_id)sem; } os_semaphore_id osi_createbinarysemaphore(const char *name, UINT32 options, BOOL flag) { SemType *sem; sem=(SemType *)osi_calloc(sizeof(SemType)); if (sem==NULL) { return 0; } strncpy(sem->name, name, SIZE_SEM_NAME-1); sem->type=SEM_BINARY; sem->nRecursive=0; sem->owner=0; sem->handler=(OS_EVENT*)OSSemCreate(flag==TRUE?1:0); if (sem->handler == 0) { osi_free(sem); return 0; } // OSSaveUserData((OS_EVENT *)sem->handler, sem); trace_sem_create(binary); return (os_semaphore_id)sem; } os_semaphore_id osi_createmutexsemaphore(const char *name) { //BKNOTE: uCOS-II¿¡¼­ Á¦°øÇÏ´Â OSMutexCreate() »ç¿ëÇÒ Çʿ䰡 ÀÖ´ÂÁö È®ÀÎ ¿äÇÔ #if USE_BCM_MUTEX SemType *sem; BERR_Code eResult = BERR_SUCCESS; BKNI_MutexHandle hMutex = NULL; sem=(SemType *)osi_calloc(sizeof(SemType)); if (sem==NULL) { return 0; } eResult = BKNI_CreateMutex(&hMutex); if ((BERR_SUCCESS != eResult) || (NULL == hMutex)) { osi_free(sem); return 0; } strncpy(sem->name, name, SIZE_SEM_NAME-1); sem->type=SEM_MUTEX; sem->nRecursive=0; sem->owner=0; sem->hMutex=hMutex; #else SemType *sem; sem=(SemType *)osi_calloc(sizeof(SemType)); if (sem==NULL) { return 0; } strncpy(sem->name, name, SIZE_SEM_NAME-1); sem->type=SEM_MUTEX; sem->nRecursive=0; sem->owner=0; sem->handler=(OS_EVENT*)OSSemCreate(1); if (sem->handler == 0) { osi_free(sem); return 0; } // OSSaveUserData((OS_EVENT *)sem->handler, sem); #endif trace_sem_create(mutex); return (os_semaphore_id)sem; } #if COMMENT _______(){} #endif /* free list of reuse semaphore. linked list. LIFO. */ void *g_os_free_sem_list; int osi_free_reuse_sem_count(void) { UINT32 flags; SemType *sem; int count = 0; flags = MIPS_SetInterrupts(OS_DISABLE); // OS_ENTER_CRITICAL(flags); sem = (SemType *) g_os_free_sem_list; while (sem) { count++; sem = (SemType *)sem->next; } MIPS_SetInterrupts(flags);// OS_EXIT_CRITICAL(flag); return count; } os_semaphore_id osi_create_reuse_semaphore(char *name, int count) { os_semaphore_id sid; UINT32 flags; SemType *sem = NULL; flags = MIPS_SetInterrupts(OS_DISABLE); // OS_ENTER_CRITICAL(flags); if (g_os_free_sem_list) { sem = (SemType *)g_os_free_sem_list; g_os_free_sem_list = sem->next; } MIPS_SetInterrupts(flags);// OS_EXIT_CRITICAL(flag); if (sem && sem->handler) { // ok! reuse it! strncpy(sem->name, name, SIZE_SEM_NAME-1); sem->type=SEM_COUNTING; sem->nRecursive=0; sem->owner=0; sem->next = 0; //BKNOTE: À̺κÐÀ» ¾î¶»°Ô ó¸®ÇØ¾ß Çϳª.. OSSaveUserData((OS_EVENT *)sem->handler, sem); trace_sem_create(count); // match initial 'count' value. ((OS_EVENT *)(sem->handler))->OSEventCnt = count; sid = (os_semaphore_id)sem; } else { sid = osi_createcountingsemaphore(name, 0, count); } return sid; } void osi_delete_reuse_semaphore(os_semaphore_id sid) { /* necessary condition for deleting. no task should be pending for this semaphore. */ UINT32 flags; SemType *sem = (SemType *)sid; if (sem->type != SEM_COUNTING) { printf("!! %s: only csem should be reusable.\n", __FUNCTION__); return; } flags = MIPS_SetInterrupts(OS_DISABLE); // OS_ENTER_CRITICAL(flags); sem->next = (void *) g_os_free_sem_list; g_os_free_sem_list = sem; MIPS_SetInterrupts(flags);// OS_EXIT_CRITICAL(flag); } #if COMMENT ____MsgQ____(){} #endif #define MFIFO_INIT(fifo, size) do {(fifo)->bf_wrap=0; \ (fifo)->bf_read=(fifo)->bf_write=0;\ (fifo)->bf_last=(size);}while(0) #define MFIFO_WRITE_PTR(fifo) ((fifo)->q_buf + ((fifo)->bf_write)*((fifo)->item_sz)) #define MFIFO_READ_PTR(fifo) ((fifo)->q_buf + ((fifo)->bf_read)*((fifo)->item_sz)) // availabe free slots in queue. #define MFIFO_WRITE_PEEK(fifo) \ /* |====W---R===| */ ((unsigned)(((fifo)->bf_write < (fifo)->bf_read) ? (fifo)->bf_read - (fifo)->bf_write : ( \ /* |---R===W---| */ ((fifo)->bf_write > (fifo)->bf_read) ? (fifo)->bf_last - (fifo)->bf_write : ( \ /* |---RW---| */ (fifo)->bf_wrap ? 0 : (fifo)->bf_last - (fifo)->bf_write)))) // current message items in queue. #define MFIFO_READ_PEEK(fifo) \ /* |====W---R===| */ ((unsigned)(((fifo)->bf_write < (fifo)->bf_read) ? (fifo)->bf_last - (fifo)->bf_read : ( \ /* |---R===W---| */ ((fifo)->bf_write > (fifo)->bf_read) ? (fifo)->bf_write - (fifo)->bf_read : ( \ /* |---RW---| */ (fifo)->bf_wrap ? (fifo)->bf_last - (fifo)->bf_read:0)))) /// write to fifo. for our case, increment size is always 1. #define MFIFO_WRITE_COMMIT(fifo) do { \ /*BDBG_ASSERT(MFIFO_WRITE_PEEK(fifo) >= 1);*/ \ (fifo)->bf_write += 1; \ if ((fifo)->bf_write >= (fifo)->bf_last) {(fifo)->bf_write = 0;(fifo)->bf_wrap++;} \ } while(0) /// read out from fifo. for our case, increment size is always 1. #define MFIFO_READ_COMMIT(fifo) do { \ /*BDBG_ASSERT(MFIFO_READ_PEEK(fifo) >= 1);*/ \ (fifo)->bf_read += 1; \ if ((fifo)->bf_read >= (fifo)->bf_last) {(fifo)->bf_read = 0;(fifo)->bf_wrap--;} \ } while(0) /* MsgqType µµ SemType ÀÇ ¾ÕºÎºÐ°ú µ¿ÀÏÇÑ ±¸Á¶¸¦ ÃëÇÑ´Ù. ¸ðµÎ uCOS ÀÔÀå¿¡¼­ µ¿ÀÏÇÑ osi event typeÀ¸·Î ó¸® °¡´É. */ typedef struct { UINT8 type; UINT32 handler; // actually, this is os couting semaphore char name[SIZE_SEM_NAME+1]; //--------- UINT32 dummy_guard; os_messagequeue_id csem; // counting semaphore for messages os_messagequeue_id mutex; // access mutex for this queue. UINT16 item_sz; // only support uniform size. UINT16 max_num_item; // maximum number of items that this queue can have. //UINT16 num_item; // number of message items currently exist in queue. // fifo implementation. //struct osi_q_fifo fifo; UINT16 bf_write; // this is index, not pointer. UINT16 bf_read; UINT16 bf_last; // same as max_num_item. int bf_wrap; UINT8 *q_buf; } MsgqType; void osi_printmessagequeue(MsgqType *msgq) { } void osi_deletemessagequeue(os_messagequeue_id qid) { #if USE_BCM_MSG_QUEUE b_queue_t* p_msg_queue = (b_queue_t*)(qid); bos_delete_queue(p_msg_queue); OS_FreeDirect(&p_msg_queue); #else printf("!! %s: delete queue not supported!!\n", __FUNCTION__); #endif } //BKTODO: ucOS-II¿¡¼­ Á¦°øÇÏ´Â OSQCreate/OSQPost/OSQPend µîÀ» warpÇÑ bos_create_queue/bos_post_event/bos_pend_event·Î ±³Ã¼ÇÒÁö ¿©ºÎ. os_messagequeue_id osi_createmessagequeue(const char *name, UINT32 options, UINT32 maxMessages, UINT32 maxMessageLength) { #if USE_BCM_MSG_QUEUE b_queue_t* p_msg_queue= (b_queue_t*)OS_Malloc(sizeof(b_queue_t)); //BKNOTE: OS°¡ »ç¿ëÇÒ memory¸¦ ÇÒ´çÇÔ.. ÁÖÀÇ (osi_deletemessagequeue ¿¡¼­µµ ÇØÁ¦µÇÁö ¾Ê´Â´Ù.. ) b_event_t * p_bufferQ = (b_event_t *)OS_Malloc(maxMessages*maxMessageLength); if(bos_create_queue(p_msg_queue, p_bufferQ, maxMessages)!=b_ok) { printf("FATAL: bos_create_queue\n"); }else { printf("Q[%s] create 0x%x\n", p_msg_queue); } return (os_messagequeue_id)p_msg_queue; #else MsgqType *msgq; char buf[SIZE_SEM_NAME+10]; os_semaphore_id csem = 0; #if !BUGFIX_MSGQ os_semaphore_id mutex = 0; #endif if (maxMessages > 65535) { printf("!! %s: max msg exceed limit\n", __FUNCTION__); return (os_messagequeue_id)NULL; } if (name == NULL) name = ""; // create csem.. strcpy(buf, "S:"); strncpy(buf+2, name, SIZE_SEM_NAME-2); csem = osi_createcountingsemaphore(buf, 0, 0); if (csem == 0) { return (os_messagequeue_id)NULL; } #if !BUGFIX_MSGQ // create mutex.. strcpy(buf, "M:"); strncpy(buf+2, name, SIZE_SEM_NAME-2); mutex = osi_createmutexsemaphore(buf); if (mutex == 0) { osi_deletesemaphore(csem); return (os_messagequeue_id)NULL; } #endif // to avoid memory frag, we alloc only one chunk of memory. msgq = (MsgqType *) osi_calloc(sizeof(MsgqType) + maxMessages*maxMessageLength); if (msgq == NULL) { printf("!! %s: out of mem for queue\n", __FUNCTION__); // oops! we cannot delete mutex sem! osi_deletesemaphore(csem); #if !BUGFIX_MSGQ osi_deletesemaphore(mutex); #endif return (os_messagequeue_id)NULL; } msgq->type = SEM_MSGQ; msgq->handler = ((SemType *)csem)->handler; msgq->dummy_guard = 0xcafe2008; msgq->csem = csem; #if !BUGFIX_MSGQ msgq->mutex = mutex; #endif msgq->item_sz = maxMessageLength; msgq->max_num_item = maxMessages; //msgq->num_item = 0; msgq->q_buf = ((UINT8 *)msgq + sizeof(MsgqType)); MFIFO_INIT(msgq, msgq->max_num_item); if (name && name[0]) strncpy(msgq->name, name, SIZE_SEM_NAME-1); else msgq->name[0] = 0; // override mutex user data with queue's pointer. // OSSaveUserData((OS_EVENT *)msgq->handler, msgq); return (os_messagequeue_id)msgq; #endif } int osi_sendmessage(os_messagequeue_id qid, void *buffer, int nBytes) { #if USE_BCM_MSG_QUEUE b_queue_t* p_msg_queue = (b_queue_t*)(qid); printf("Q send 0x%x\n", p_msg_queue); bos_post_event(*p_msg_queue, (b_event_t *)buffer); return DHL_OK; #else DHL_RESULT result = DHL_OK; MsgqType *msgq = (MsgqType *)qid; #if BUGFIX_MSGQ UINT32 flags; #endif #if BUGFIX_MSGQ flags = MIPS_SetInterrupts(OS_DISABLE); // OS_ENTER_CRITICAL(flags); #else osi_takemutexsemaphore_wait(msgq->mutex, WAIT_FOREVER); #endif if (MFIFO_WRITE_PEEK(msgq) > 0) { memcpy(MFIFO_WRITE_PTR(msgq), buffer, min(nBytes, msgq->item_sz)); MFIFO_WRITE_COMMIT(msgq); #if OSAL_DEBUG printf("#### queue send, q %x, '%s' h %x, r%d w%d\n", msgq, msgq->name, msgq->handler, msgq->bf_read, msgq->bf_write); #endif osi_givesemaphore(msgq->csem); // now, some other task will wake up. } else { // fifo full! result = DHL_FAIL_NOT_AVAILABLE; } #if BUGFIX_MSGQ MIPS_SetInterrupts(flags);// OS_EXIT_CRITICAL(flags); #else osi_givemutexsemaphore(msgq->mutex); #endif return result; #endif } int osi_receivemessage(os_messagequeue_id qid, void *msgBuf) { #if USE_BCM_MSG_QUEUE b_queue_t* p_msg_queue = (b_queue_t*)(qid); b_event_t * p_event = bos_pend_event(*p_msg_queue,-1); if(p_event==NULL) { msgBuf = NULL; return DHL_FAIL_TIMEOUT; }else { msgBuf = (void *)p_event; return DHL_OK; } #else return osi_receivemessage_wait(qid, msgBuf, WAIT_FOREVER); #endif } /* note! receive message usually used in one task. */ //int osi_receivemessage_wait(os_messagequeue_id qid, void *msgBuf, int maxLen, int *msgLen, int ticks) int osi_receivemessage_wait(os_messagequeue_id qid, void *msgBuf, int ticks) { #if USE_BCM_MSG_QUEUE b_queue_t* p_msg_queue = (b_queue_t*)(qid); b_event_t * p_event = bos_pend_event(*p_msg_queue,ticks /*not ticks, it's msec*/); if(p_event==NULL) { msgBuf = NULL; return DHL_FAIL_TIMEOUT; }else { msgBuf = (void *)p_event; return DHL_OK; } #else DHL_RESULT result = DHL_OK; MsgqType *msgq = (MsgqType *)qid; BOOL bexit = FALSE; #if BUGFIX_MSGQ UINT32 flags; #endif while (bexit == FALSE) { result = osi_takesemaphore_wait(msgq->csem, ticks); if (result == DHL_FAIL_TIMEOUT) break; if (result != DHL_OK) { printf("!! %s: unexpected err 0x%x in take csem\n", __FUNCTION__, result); break; } #if OSAL_DEBUG printf("#### queue receive, q %x, '%s' h %x\n", msgq, msgq->name, msgq->handler); #endif // if csem is taken, it means that there are available messages in the queue. #if BUGFIX_MSGQ flags = MIPS_SetInterrupts(OS_DISABLE); // OS_ENTER_CRITICAL(flag); #else osi_takemutexsemaphore_wait(msgq->mutex, WAIT_FOREVER); #endif if (MFIFO_READ_PEEK(msgq) > 0) { // int copyLen = min(maxLen, msgq->item_sz); int copyLen = msgq->item_sz; memcpy(msgBuf, MFIFO_READ_PTR(msgq), copyLen); MFIFO_READ_COMMIT(msgq); result = DHL_OK; bexit = TRUE; } else { // fifo empty?? printf("!! %s: csem taken, but queue empty?\n", __FUNCTION__); osi_printmessagequeue(msgq); } #if BUGFIX_MSGQ MIPS_SetInterrupts(flags);// OS_EXIT_CRITICAL(flags); #else osi_givemutexsemaphore(msgq->mutex); #endif } return result; #endif } int osi_receivemessage_nowait(os_messagequeue_id qid, void *msgBuf) { return osi_receivemessage_wait(qid, msgBuf, NO_WAIT); } #if COMMENT ____Memory____(){} #endif #if OSAL_HEAP_DEBUG #warning build osal with OSAL_HEAP_DEBUG option. void *os_dbg_malloc(int size, char *file, int line) { // just call ministd api. return malloc_align_dbg(size, 2, file, line); } void *os_dbg_calloc(int n, int m, char *file, int line) { void *p; p = malloc_align_dbg(n*m, 2, file, line); if (p) memset(p, 0, n*m); return p; } void os_dbg_free(void *ptr, char *file, int line) { void **pptr = (void **)ptr; if (pptr == NULL) return; // cafrii 081006 add if (*pptr == NULL) return; // already free()'ed pointer? free_dbg(*pptr, file, line); *pptr = NULL; } #else // OSAL_HEAP_DEBUG #undef malloc #undef calloc #undef free void *OS_Malloc(int size) { void* p = malloc(size); return p; } void OS_FreeDirect(void *ptr) { free(ptr); } void *OS_Calloc(int n, int m) { void *p; p = OS_Malloc(n*m); if (p) memset(p, 0, n*m); return p; } void OS_Free(void *ptr) { void *p; if (ptr == NULL) return; p = *(void **)ptr; OS_FreeDirect(p); } #endif extern bcm_heap_t *g_p_sdram_heap; void dump_heap(int threshold) { #ifdef BCM_DEBUG // show all heap blocks, greater than threshold. mem_reportbrief_ex(g_p_sdram_heap, threshold); #endif } void os_heap_status(dhl_heap_status *pstat) { #ifdef BCM_DEBUG struct bcm_heap_status bhs; memset(pstat, 0, sizeof(dhl_heap_status)); if (mem_status(g_p_sdram_heap, &bhs) == 0) { pstat->size_heap = bhs.size_heap; pstat->num_alloc_chunk = bhs.num_alloc_chunk; pstat->size_alloc = bhs.size_alloc; pstat->num_free_chunk = bhs.num_free_chunk; pstat->size_free = bhs.size_free; } #endif } #if COMMENT ____Debug____(){} #endif #undef printf // do not add tag. #if 0 char *osi_get_eventinfo(void *p, char *outbuf, int outbuflen) { int k; OS_EVENT *pevent = (OS_EVENT *)p; SemType *sem; UBYTE *t; char buf[3*16 + 20]; if (pevent == NULL) { //printf("\t --> no event\n"); outbuf[0] = 0; return outbuf; } sem = (SemType *)OSGetUserData(pevent); if (sem == NULL) { // this event is not created by our OSAL. maybe it belongs driver code. // then, we track more using pevent itself. snprintf(outbuf, outbuflen, "%s event %x", pevent->OSEventPtr ? "que/mbox" : "sem", // uCOS internal. (int)pevent); return outbuf; } buf[0] = 0; if (pevent) { t = pevent->OSEventTbl; for (k=0; k<63; k++) { if (t[k/8] & (1<<(k%8))) sprintf(buf + strlen(buf), "%d ", k); } // this is pending task list. } snprintf(outbuf, outbuflen, "%s '%s' w-list %s", sem->type == SEM_MUTEX ? "mtx" : sem->type == SEM_BINARY ? "bsm" : sem->type == SEM_COUNTING ? "csm" : sem->type == SEM_MSGQ ? "que" : "???", sem->name, buf); return outbuf; } #endif void osi_show_taskinfo(int level) { // bos_print_taskinfo_ex(level, osi_get_eventinfo); bos_print_taskinfo(); } /* end of file */