/******************************************************************* * DMW_Mutex.c * * General Purpose Mutex * * Copyright 2003 Digital STREAM Technology, Inc. * All Rights Reserved * * $Id: DMW_Mutex.c,v 0.12 2004 cafrii Exp $ * ********************************************************************/ #include "DMW_Platform.h" #if 1 //#include #endif #include "DMW_Mutex.h" DHL_MODULE("$mtx", 0); #define DMW_MUTEX_TEST 1 #if COMMENT ____Example_Code____(){} /* Mutex = { SemID, Owner, lockCnt, FailCnt, UseOsMutex, Name, flag, traceLvl } */ DMW_MUTEX mcmMutex = { 0, 0, 0, 0, FALSE, "McmMtx", OS_SEM_PRIO, 1, }; STATUS lock_mcm(int timeout) { return DMW_LockMutexWait(&mcmMutex, timeout); } void unlock_mcm() { DMW_UnlockMutex(&mcmMutex); } #endif /*.......................... */ void DMW_PrintMutex(DMW_MUTEX *pMutex) { DHL_OS_TASK_INFO tInfo; DHL_OS_Printf("\t pMutex : 0x%x\n", pMutex); if (pMutex) { DHL_OS_Printf("\t semId: 0x%x\n", pMutex->semId); DHL_OS_Printf("\t lockCount: %d\n", pMutex->lockCount); DHL_ASSERT(DHL_OS_GetTaskInfo(DHL_OS_GetTaskID(), &tInfo)==DHL_OK , "!!DHL_OS_GetTaskInfo Error"); DHL_OS_Printf("\t ownerTask: 0x%x, %s\n", pMutex->ownerTaskId, tInfo.name); DHL_OS_Printf("\t FailCount: %d\n", pMutex->initFailCount); DHL_OS_Printf("\t name: %s\n", pMutex->name); DHL_OS_Printf("\t %sMutex, traceLvl %d, %s\n", pMutex->useOsMutex ? "Os" : "Mw", pMutex->traceLevel, pMutex->flag & OS_SEM_PRIO ? "Priority" : "FIFO"); } DHL_OS_Printf("\n"); } /* debug util */ void DMW_SetMutexTraceLevel(DMW_MUTEX *pMutex, int traceLevel) { if (pMutex && pMutex->semId) pMutex->traceLevel = traceLevel; DMW_PrintMutex(pMutex); } /* debug util */ DHL_OS_TASK_ID DMW_GetOwnerTaskId(DMW_MUTEX *pMutex) { if (pMutex && pMutex->semId && pMutex->lockCount > 0) return pMutex->ownerTaskId; return 0; } STATUS DMW_InitMutex(DMW_MUTEX *pMutex, char *name) { DHL_OS_SEMA_ID mysema4; if (pMutex == NULL) { dprint(0, "!! Null argument in DMW_InitMutex\n"); return statusInvalidArgument; } /* pSem¿¡ ÀÖ´Â sema4°¡ Á¦´ë·Î µÈ °ÍÀÎÁö È®ÀÎÇÑ´Ù. */ if (pMutex->semId) { dprint(2, "Sema4 %x, %s Already inited.\n", pMutex->semId, pMutex->name); return statusOK; /* already initialized. do nothing. */ } if (pMutex->initFailCount < 5) { if (name == NULL || name[0] == 0) { /* À̸§À» ÁöÁ¤ÇÏÁö ¾Ê¾ÒÀ» °æ¿ì ÀÌ ÇÔ¼ö¿¡¼­ ÀÓÀÇ À̸§À» Áִ°͵µ ±¦Âú´Ù. */ /* sprintf(pMutex->name, "%s%d", OS_TaskName(0), DHL_OS_GetMsCount()%10); */ } else { strncpy(pMutex->name, name, MAX_MUTEX_NAME-1); pMutex->name[MAX_MUTEX_NAME-1] = 0; } if (pMutex->useOsMutex) { mysema4 = DHL_OS_CreateMutexSemaphore(pMutex->name); } else { mysema4 = DHL_OS_CreateBinarySemaphore(pMutex->name, OS_SEM_PRIO, TRUE); /* OS_SEM_FIFO --> OS_SEM_PRIO */ /* ¾Æ¹«³ª ¸ÕÀú ±ÞÇÑ task°¡ print¸¦ ÇÒ ¼ö ÀÖµµ·Ï. */ } if (mysema4 == (DHL_OS_SEMA_ID)NULL) { dprint(0, "!! Sema4 '%s' creation failed.\n", pMutex->name); pMutex->initFailCount++; /* semaphore°¡ ¾ø¾îµµ ÀÏ´Ü ÁøÇàÀº ½Ã۵µ·Ï ÇÑ´Ù. */ return statusOutOfResource; } /* Semaphore »ý¼º ¼º°ø. ÀÌÁ¦ »ý¼ºµÈ sema4¸¦ pSem¿¡ ¾ÈÀüÇÏ°Ô assignÇÑ´Ù. // ThreadX¿¡¼­´Â OS_LockTask ÀÚü°¡ Mutex¸¦ ÀÌ¿ëÇÏ´Â ¹æ½ÄÀ¸·Î ±¸ÇöµÇ¾ú±â ¶§¹®¿¡ // InitMutex¿¡¼­ ´Ù½Ã OS_LockTask¸¦ È£ÃâÇÒ ¼ö ¾ø´Ù.. */ if (1) { UINT32 mask; mask = DHL_OS_DisableInterrupts(); if (pMutex->semId == 0) { /* OS_LockTask µÈ »óÅ¿¡¼­ ÃʱâÈ­ ÇÑ´Ù. */ pMutex->semId = mysema4; mysema4 = (DHL_OS_SEMA_ID)NULL; } DHL_OS_RestoreInterrupts(mask); } /* OS_LockTask/OS_UnlockTask »çÀÌ¿¡¼­ swapÀ» Çߴµ¥µµ ¾ÆÁ÷ ±×´ë·ÎÀ̸é // ÀÌ¹Ì pSemÀÌ ´Ù¸¥ ŽºÅ©¿¡ ÀÇÇØ »ý¼ºÀÌ µÈ °æ¿ìÀÌ´Ù. Áߺ¹ »ý¼ºµÇ¾úÀ¸¹Ç·Î Çϳª¸¦ »èÁ¦ÇØ¾ß ÇÑ´Ù. */ if (mysema4) { dprint(0, "!! Simultaneous '%s' Sema4 Creation detected %x. Safe release ours %x\n", pMutex->name, pMutex->semId, mysema4); DHL_OS_DeleteSemaphore(mysema4); mysema4 = (DHL_OS_SEMA_ID)NULL; } else { dprint(2, "Sema4 %x, '%s' created. DMW_Mutex 0x%x\n", pMutex->semId, pMutex->name, (int)pMutex); } return statusOK; } else { return statusOutOfResource; } } #if 0 /* for reference */ Table 2-1: Task State Transitions -------------------------------------------------------------------------------- State Symbol Description -------------------------------------------------------------------------------- READY The state of a task that is not waiting for any resource other than the CPU. PEND The state of a task that is blocked due to the unavailability of some resource. DELAY The state of a task that is asleep for some duration. SUSPEND The state of a task that is unavailable for execution. This state is used primarily for debugging. Suspension does not inhibit state transition, only task execution. Thus pended-suspended tasks can still unblock and delayed-suspended tasks can still awaken. DELAY + S The state of a task that is both delayed and suspended. PEND + S The state of a task that is both pended and suspended. PEND + T The state of a task that is pended with a timeout value. PEND + S + T The state of a task that is both pended with a timeout value and suspended. state + I The state of task specified by state, plus an inherited priority. #endif #ifndef WIND_READY #define WIND_READY 0x00 /* ready to run */ #define WIND_SUSPEND 0x01 /* explicitly suspended */ #define WIND_PEND 0x02 /* pending on semaphore */ #define WIND_DELAY 0x04 /* task delay (or timeout) */ #define WIND_DEAD 0x08 /* dead task */ #endif STATUS DMW_LockMutex(DMW_MUTEX *pMutex) { return DMW_LockMutexWait(pMutex, 0x7fffffff); /* wait forever */ } STATUS DMW_LockMutexWait(DMW_MUTEX *pMutex, int timeout) { /* timeout 0À» ÁöÁ¤Çϸé WAIT_FOREVER°¡ ¾Æ´Ï¶ó NoWait°¡ µÇ¹ö¸²¿¡ À¯ÀÇ. */ int nWaitCount = 0; int err; DHL_OS_TASK_ID mytid; // DHL_OS_TASK_INFO tInfo; int ticksToWait, ticksLeft, tickMonitorPeriod; mytid = DHL_OS_GetTaskID(); /* ÇöÀç task ID */ /* mutex¸¦ »ý¼ºÇÏ´Â °úÁ¤Àº ¾à°£Àº 'ºÎ´ã'µÇ´Â ÀÏÀÌ´Ù. (OS_LockTask/OS_UnlockTask, sema4 ¸®½ºÆ® °ü¸® µî..) // ¸¸¾à ¸®¼Ò½º ºÎÁ· µîÀÇ ÀÌÀ¯·Î sema4»ý¼ºÀÌ ½ÇÆÐÇß¾ú´Ù¸é, ±× ÀÌÈÄ °è¼Ó »ý¼ºÀ» ½Ãµµ ÇÏ´Â °Í ¶ÇÇÑ // ºñ½ÁÇÑ ÀÌÀ¯·Î ½ÇÆÐÇÒ °¡´É¼ºÀÌ Å©´Ù. // ÀÏÁ¤ Ƚ¼ö ÀÌ»ó sema4 »ý¼º¿¡ ½ÇÆÐÇÑ °æ¿ì¶ó¸é ÀÌÈÄ¿¡´Â ´Ù½Ã »ý¼º ½Ãµµ¸¦ ÇÏÁö ¸»µµ·Ï ÇÑ´Ù. */ if (pMutex == NULL) { dprint(0, "!! NULL sema4 in DMW_LockMutex\n"); return statusInvalidArgument; } if (pMutex->semId == 0) { STATUS r = DMW_InitMutex(pMutex, 0); dprint(2, "Sema4 '%s' created, result %d\n", pMutex->name, r); } /* Semaphore wait¿¡¼­ OS_TakeSemaphore() ÇÔ¼ö¸¦ »ç¿ëÇÏÁö ¾Ê°í // ÁÖ±âÀûÀ¸·Î wakeup ÇÏ¿© Semaphore Take ÀÛ¾÷ »óȲÀÌ ¾î¶²Áö º¸°íÇϵµ·Ï ÇÑ´Ù. // µð¹ö±ë ¿ëµµÀ̹ǷΠcheck ÁÖ±â´Â ÃæºÐÈ÷ Ä¿µµ »ó°ü ¾ø´Ù. 1ÃÊ ¹Ì¸¸ÀÇ °ªÀº »ç¿ëÇÏÁö ¸»µµ·Ï ÇÏÀÚ. */ ticksLeft = timeout; tickMonitorPeriod = 1000; while (1) { /* mutex semaphoreÀÇ multiple-take¸¦ Èä³»³»±â À§Çؼ­ wait Çϱâ Àü¿¡ ÀÌ¹Ì ÀÚ½ÅÀÇ task¿¡¼­ // semaphore°¡ takeµÇ¾ú´ÂÁö üũÇÑ´Ù. */ if (pMutex->useOsMutex == 0 && pMutex->ownerTaskId == mytid && pMutex->lockCount > 0) { /* ÀÌ¹Ì ÇöÀç task¿¡¼­ ÀÌ Sema4¸¦ takeÇϰí ÀÖ´Ù°í ÆÇ´Ü.. */ pMutex->lockCount++; if (pMutex->traceLevel) dprint(2, "+ FakeLock '%s' B-sema4 in task %08x, lock count %d\n", pMutex->name, mytid, pMutex->lockCount); return statusOK; } ticksToWait = ticksLeft > tickMonitorPeriod ? tickMonitorPeriod : ticksLeft; if (ticksToWait <= 0) err = DHL_OS_TakeSemaphore(pMutex->semId, 0); else err = DHL_OS_TakeSemaphore(pMutex->semId, ticksToWait); if (err == 0) { /* OK! semaphore is available and we take it! */ pMutex->ownerTaskId = mytid; pMutex->lockCount++; if (pMutex->traceLevel) dprint(2, "+ Lock '%s' %c-sema4 in task %08x, lock count %d\n", pMutex->name, pMutex->useOsMutex ? 'M' : 'B', mytid, pMutex->lockCount); /* ¿øÇÏ´Â ¸ñÀûÀ» ´Þ¼ºÇßÀ¸¹Ç·Î ·çÇÁ Á¾·á. */ return statusOK; } ticksLeft -= ticksToWait; if (timeout > 0 && ticksLeft <= 0) { /* timeout ¹ß»ý.. */ if (pMutex->traceLevel) dprint(2, "'%s' %c-sema4 wait timeout!\n", pMutex->name, pMutex->useOsMutex ? 'M' : 'B'); return statusTimeout; } /* Semaphore ¸ð´ÏÅ͸µ ÄÚµå.. // // sema4¸¦ ±â´Ù¸®´Â µ¿¾È ¾î´À ŽºÅ©°¡ ÇöÀç sema4¸¦ Á¡À¯Çϰí ÀÖ´ÂÁö Ç¥½Ã. // Ȥ½Ã sema4 °ü¸®°¡ ²¿¿©¼­ hangµÉ °æ¿ì À¯¿ëÇÏ°Ô »ç¿ëµÉ ¼ö ÀÖ´Ù. // ¸Þ¼¼Áö¸¦ Ç¥½ÃÇØÁÖ´Â ÁÖ±â´Â ´õ ±æ°Ô Àâ¾Æµµ »ó°ü¾øÀ½. */ if (pMutex->traceLevel) { //DHL_ASSERT(DHL_OS_GetTaskInfo(pMutex->ownerTaskId, &tInfo)==DHL_OK // , "!!DHL_OS_GetTaskInfo Error"); // int i=3; //dprint(2, "[%x] '%s' Sema4 owner: %s, %x, wait %d\n", // mytid, pMutex->name, // pMutex->ownerTaskId ? tInfo.name: "None", // pMutex->ownerTaskId, // nWaitCount); } ++nWaitCount; /* cafrii 060919 fix.. */ /* // Error Detection code // // »ó½ÄÀûÀÎ ½Ã°£ ÀÌ»óÀ¸·Î Semaphore°¡ °è¼Ó ´Ù¸¥ task¿¡ ÀÇÇØ Á¡À¯µÇ°í ÀÖ´Ù¸é À̰ÍÀº ¹®Á¦´Ù. // Sema4 Á¡À¯Çϰí Àִ ŽºÅ© Á¤º¸¸¦ ÁÖ±âÀûÀ¸·Î Ãâ·ÂÇϵµ·Ï ÇÏ¿© µð¹ö±ë¿¡ µµ¿òÀ» ÁÙ¼ö ÀÖµµ·Ï ÇÑ´Ù. */ if (nWaitCount > 10 && pMutex->ownerTaskId) { // cafrii 090717 // ±×³É ´Ü¼øÇÏ°Ô Æ¯Á¤ mutex lock ÀÌ ºñÁ¤»óÀûÀ¸·Î ±æ¾îÁö°í ÀÖ´Ù´Â »ç½Ç¸¸ ¾Ë·ÁÁÖ°í, // °³¹ßÀÚ´Â shell ¿¡¼­ º°µµÀÇ µð¹ö±ë ·çƾÀ» ÀÌ¿ëÇÏ¿© Á¤º¸¸¦ ȹµæÇϵµ·Ï ÇÏÀÚ. /* ±× ¹Û¿¡ ´õ Ãß°¡ Á¤º¸¸¦ ¾òÀ» ¼ö ÀÖ´Ù¸é À̰÷¿¡ Ãß°¡. */ /* ¶Ç´Â ÀÚµ¿À¸·Î ¹®Á¦¸¦ RecoverÇÒ ¼ö ÀÖ´Â ¹æ¹ýÀÌ ÀÖ´Ù¸é À̰÷¿¡ Ãß°¡. */ } } /* end of Same4 Wait Loop */ } void DMW_UnlockMutex(DMW_MUTEX *pMutex) { DHL_OS_TASK_ID mytid; // DHL_OS_TASK_INFO tInfo; mytid = DHL_OS_GetTaskID(); if (pMutex == NULL) { dprint(0, "!! NULL Sema4 in DMW_UnlockMutex\n"); return; } if (pMutex->semId == 0) { dprint(0, "!! Uninitialized Sema4 in DMW_UnlockMutex\n"); return; } pMutex->lockCount--; if (pMutex->traceLevel) { if (pMutex->useOsMutex == 0 && pMutex->lockCount > 0) dprint(2, "- FakeUnlock '%s' B-sema4 in task %08x, lock count %d\n", pMutex->name, mytid, pMutex->lockCount); else dprint(2, "- Unlock '%s' %c-sema4 in task %08x, lock count %d\n", pMutex->name, pMutex->useOsMutex ? 'M' : 'B', mytid, pMutex->lockCount); } if (pMutex->lockCount < 0) { dprint(0, "!! Warning!! Negative lock count %d !, name=%s\n", pMutex->lockCount, pMutex->name); } if (mytid != pMutex->ownerTaskId) { //DHL_ASSERT(DHL_OS_GetTaskInfo(pMutex->ownerTaskId, &tInfo)==DHL_OK // , "!!DHL_OS_GetTaskInfo Error"); //dprint(0, "!! Warning!! try unlock from not owner! current owner %s, %08x\n", // tInfo.name, pMutex->ownerTaskId); } if (pMutex->lockCount <= 0) { pMutex->ownerTaskId = 0; } /* Mutex semaphoreÀÇ °æ¿ì¶ó¸é unlock ÇÒ¶§¸¶´Ù give¸¦ Çϰí, // Binary sema4¶ó¸é ¸ðµç lock count°¡ Ç®¸± °æ¿ì¿¡¸¸ give¸¦ ÇÑ´Ù. */ if (pMutex->useOsMutex || pMutex->lockCount <= 0) DHL_OS_GiveSemaphore(pMutex->semId); } void DMW_DeleteMutex(DMW_MUTEX *pMutex) { if (pMutex == NULL) { dprint(0, "!! NULL Mutex in DMW_UnlockMutex\n"); return; } if (pMutex->semId == 0) { dprint(0, "!! NULL semId in DMW_UnlockMutex\n"); return; } dprint(2, "Sema4 '%s' deleted..\n", pMutex->name); if (1) { // cafrii 091221 fix // isr lock (disabled) »óÅ¿¡¼­ os_deletesemaphore() µîÀ» Á÷Á¢ È£ÃâÇÏÁö ¾Ê´Â´Ù. // linux usermode °°Àº °æ¿ì memfree °°Àº ÇÔ¼ö¸¦ isrlock »óÅ¿¡¼­ È£ÃâÇÒ ¼ö ¾øÀ½. #if 1 DHL_OS_SEMA_ID sem; UINT32 mask = DHL_OS_DisableInterrupts(); sem = pMutex->semId; pMutex->semId = 0; DHL_OS_RestoreInterrupts(mask); if (sem) DHL_OS_DeleteSemaphore(sem); #else UINT32 mask = DHL_OS_DisableInterrupts(); DHL_OS_DeleteSemaphore(pMutex->semId); pMutex->semId = 0; DHL_OS_RestoreInterrupts(mask); #endif } } #if 0 ________() #endif #if DMW_REGISTER_DEBUG_SYMBOL static DHL_SymbolTable MutexSymbols[] = { /*---- functions */ /* DHL_FNC_SYM_ENTRY(Dmc_StopVideo), */ /*---- variables */ //DHL_VAR_SYM_ENTRY(g_Trace_bMutexDebug), 0 }; #endif /* DMW_REGISTER_DEBUG_SYMBOL */ void DMW_RegisterMutexSymbols() { #if DMW_REGISTER_DEBUG_SYMBOL DHL_DBG_RegisterSymbols(MutexSymbols, DHL_NUMSYMBOLS(MutexSymbols)); #endif } #if 0 ________() #endif /*-------------------------------------------------------------------------------------------- // // OS Semaphore debugging.. */ /*================================================================= // // OS Semaphore Monitoring Task // // ÁÖ±âÀûÀ¸·Î Semaphore °¨½ÃÇÏ¿© ¿Àµ¿ÀÛ ÇÏ´Â Semaphore Á¤º¸ Ãâ·Â */ #if COMMENT ____TEST____(){} #endif #if DMW_MUTEX_TEST /*=================================================================*/ //#include /* rand(), srand() */ int gStopMutexTest = FALSE; /* Mutex = { SemID, Owner, lockCnt, FailCnt, UseOsMutex, Name, flag, trace } */ DMW_MUTEX g_TestMutex0 = { 0, 0, 0, 0, TRUE, "Sample", 0, 1 }; DMW_MUTEX *g_TestMutex = &g_TestMutex0; /* trace level 1À̹ǷÎ, ÀÌ ¸ðµâ level ¸¸ ÃæÁ·ÇÏ¸é µð¹ö±× ¸Þ½ÃÁö°¡ Ç¥½ÃµÊ. Å×½ºÆ® ÀýÂ÷: Shell> MutexTestInit Shell> sml "$MTX" 2 Shell> TestMutex Shell> set gStopMutexTest 1 // Å×½ºÆ® Á¾·á */ void MutexTestInit(void) { DHL_DBG_RegisterVarSymbol(DHL_VAR_SYM_ARGS(gStopMutexTest)); } void MutexTestTask1(UINT32 arg) { DHL_OS_Printf("**** Start Task1 **** \n"); DHL_OS_Delay(rand()%100); while (gStopMutexTest == FALSE) { DMW_LockMutex(g_TestMutex); DHL_OS_Delay(rand()%200); DMW_UnlockMutex(g_TestMutex); DHL_OS_Delay(rand()%100); } DHL_OS_Printf("**** Stop Task1 **** \n"); DHL_OS_SelfDeleteTask(); } void MutexTestTask2(UINT32 arg) { DHL_OS_Printf("**** Start Task2 **** \n"); DHL_OS_Delay(rand()%100); while (gStopMutexTest == FALSE) { DMW_LockMutex(g_TestMutex); DHL_OS_Delay(rand()%200); DMW_LockMutex(g_TestMutex); /* ÀÌÁß Lock Å×½ºÆ®.. */ DHL_OS_Delay(rand()%200); DMW_UnlockMutex(g_TestMutex); DHL_OS_Delay(rand()%100); DMW_UnlockMutex(g_TestMutex); DHL_OS_Delay(rand()%100); } DHL_OS_Printf("**** Stop Task2 **** \n"); DHL_OS_SelfDeleteTask(); } void MutexTestTask3(UINT32 arg) { DHL_OS_Printf("**** Start Task3 **** \n"); DHL_OS_Delay(rand()%100); while (gStopMutexTest == FALSE) { DMW_LockMutex(g_TestMutex); DHL_OS_Delay(rand()%200); DMW_UnlockMutex(g_TestMutex); DHL_OS_Delay(rand()%100); } DHL_OS_Printf("**** Stop Task3 **** \n"); DHL_OS_SelfDeleteTask(); } void TestMutex() { DHL_OS_Printf("g_TestMutex : 0x%x\n", g_TestMutex); srand(DHL_OS_GetMsCount()); DHL_OS_CreateTask(MutexTestTask1, "Mtx1", TASK_PRI_DHL_SHELL, 4096, 0); DHL_OS_CreateTask(MutexTestTask2, "Mtx2", TASK_PRI_DHL_SHELL+1, 4096, 0); DHL_OS_CreateTask(MutexTestTask3, "Mtx3", TASK_PRI_DHL_SHELL+2, 4096, 0); } #endif /* DMW_MUTEX_TEST */ /************************************************************************* Revision history: 0.12 2004/7/24 DeleteMutex added, bugfix 0.11 2004/05/28 add selective debug print 0.1 2004/01/01 initial coding **********************************************************************/