''' ¹®¼­ÀÇ ¼öÁ¤ ''' * ¾î¶²ÀÌ¶óµµ ÇØ´ç ¹®¼­¿¡¼­ À߸øµÈ ºÎºÐÀÌ ÀÖÀ¸¸é ±â²¨È÷ ¼öÁ¤À» ºÎŹµå¸³´Ï´Ù. ¸¹Àº Âü¿©¸¦ ÅëÇØ ÀÌ ¹®¼­°¡ µçµçÇÑ ¹Þħ¸ñÀÌ µÇ±â¸¦ ÇÊÀÚ´Â °£ÀýÈ÷ ¹Ù¶ó°í ÀÖ½À´Ï´Ù. * °³ÀÎÀûÀÎ ÀÇ°ßÀ̳ª Áß¿äÇÑ design»óÀÇ ¾ÆÀ̵ð¾î°¡ ÀÖÀ¸¸é ²À ±Û ³²°ÜÁÖ½Ã±æ ¼Ò¸ÁÇÕ´Ï´Ù. ---- = ¼±Á¡Çü ThreadÀÇ ±¸Çö = == ¸ñÂ÷ == [[TableOfContents]] == °³¿ä == * ÀÌ ¹®¼­´Â ÀϹÝÀûÀ¸·Î KernelÀÇ ÁøÀÔÁ¡°ú ±âŸ »óȲ¿¡¼­ÀÇ ÃÖ´ëÇÑ °£´ÜÇÑ ThreadÀÇ ±âÃʱ¸ÇöÀ» À§ÇÑ ³»¿ëÀ» Àû¾îº¼±î ÇÕ´Ï´Ù. * ºñ¼±Á¡Çü ThreadÀÇ °æ¿ì´Â Á» º¹ÀâÇÒ»Ó ÀÌ ³»¿ëÀ» ÀÌÇØÇÑ µ¶ÀÚ¶ó¸é ÃæºÐÈ÷ °³¼ºÀÖ´Â ¼Ò½º¸¦ âÁ¶ÇϽǼö ÀÖÀ»°Å¶ó ¹Ï¾î ÀǽÉÄ¡ ¾Ê½À´Ï´Ù. * ¼³¸í°ú ¿¹Á¦´Â C·Î ±¸¼ºÇÏ·Á°í ³ª¸§´ë·Î ³ë·ÂÇÏ°ÚÁö¸¸ ÇÊÀÚ°¡ ±¸ÇöÇÑ ½ÇÁ¦´Â 100% ¾î¼Àºí¸® ÀÔ´Ï´Ù. ±×·¯ÇÑ °úÁ¤¿¡¼­ ÀϺΠ¼º´É»ó ÃÖÀûÈ­°¡ ±â´ëÄ¡¸¸Å­ ÀÌ·ïÁöÁö ¾ÊÀ»¼ö ÀÖ½À´Ï´Ù. == ThreadÀÇ °³¿ä == * ÀÌ°ÍÀÌ ¹«¾ùÀΰí? == Thread design == === ÄÄÆÄÀÏ·¯ÀÇ ÃÖÀûÈ­¿¡ µû¸¥ ºñÀǵµÀû °á°ú === ÃÖÀûÈ­¿¡ ÀÇÇÑ Thread codeÀÇ ÀǵµµÇÁö ¾ÊÀº Çö»óÀÌ ¹ß»ýÇÒ¼öÀÖ½À´Ï´Ù. ÀÏ´Ü ±×·¯ÇÑ ºÎºÐ¿¡ ´ëÇؼ­´Â ºÒ°¡ÇÇÇÏ°Ô Assembly·Î ±¸ÇöÇÏ¿© Àú´Â ÇØ°á¹æ¹ýÀ» ¸ð»öÇÏ¿´½À´Ï´Ù. ±×·¯³ª ÇÔ¼ö ÀÚüÀÇ FrameÀÇ ÃÖÀûÈ­°¡ ÀÌ·ïÁú¶§¸é ¹æ¹ýÀÌ ³­ÇØÇÕ´Ï´Ù. ÀÌ¿¡ ´ëÇÑ °í¹ÎÀº ¹Ýµå½Ã ÇÊ¿äÇÕ´Ï´Ù. ÀÌ¿¡ ´ëÇÑ ÃæºÐÇÑ °í·Á°¡ µÇÁö ¾ÊÀ¸¸é ¿ÀÁ÷ ÀÚ½ÅÀÇ PC¿¡¼­¸¸ ½ÇÇàµÇ´Â ±âÇüÀûÀÎ Thread code°¡ µÉ°ÍÀÔ´Ï´Ù. === StackÀÇ °¡º¯Àû °ËÃâ === °¢ Thread´Â °íÀ¯ÀÇ StackÀ» ¼ÒÀ¯ÇÏ°Ô ¼³°èµË´Ï´Ù. ÇÏÁö¸¸ ±×°ÍÀÌ °íÁ¤ÀûÀ̶ó¸é Áö¿ªº¯¼ö·Î Ä¿´Ù¶õ ¹è¿­À» ¼±¾ðÇÏ¿© »ç¿ëÇϴµ¥ ºÎ´ãÀÌ ¾Æ´Ò¼ö ¾ø°Ú½À´Ï´Ù. ¶§¹®¿¡ StackÀ» °¡º¯ÀûÀ¸·Î ´Ã·ÁÁÙ¼ö ÀÖ´Â ¹æ¹ýÀÌ ¿ä±¸µË´Ï´Ù. === How to swap === ÀÌ°ÍÀº StackÀÌ SwapµÇ´Â°Í¿¡ ´ëÇÑ °í¹ÎÀÌ ÇÊ¿äÇϴٴµ¥ ÀÖ½À´Ï´Ù. ¹«Åδë°í ¸ðµÎ SwapÀÌ ¾Ë¾Æ¼­ µÇ¸é ÁÁ°ÚÁö¸¸ Àß »ý°¢Çغ¸½Ã¸é ThreadÀÇ StackÀº °ú¿¬ SwapÀÌ ÇÊ¿äÇÑ°¡¸¦ »ý°¢ÇغÁ¾ß ÇÕ´Ï´Ù. À߸øÇÏ¸é ¿ÀÈ÷·Á ºÎÀÛ¿ëÀÌ ¸¸¸¸Ä¡ ¾Ê´Ù´Âµ¥ ÁßÁ¡À» µÎ°í »ý°¢Çغ¼ ¹®Á¦ÀÓÀÌ ºÐ¸íÇÕ´Ï´Ù. ÇÊÀÚÀÇ ¼Ò°ßÀº "StackÀº Heap°ú ´Ù¸£´Ù" ÀÔ´Ï´Ù. °áÄÚ SwapÀÌ µÇÁö ¾Ê°í ¾Æ¿¹ °í·ÁµÇÁö ¾Ê´Â°ÍÀÌ ÁÁ´Ù´Â »ý°¢ÀÔ´Ï´Ù. ¿©·¯ºÐµéÀÇ »ý°¢Àº ¾î¶°½ÅÁö¿ä? °¢ÀÚ ¸¸µé¾îº¸°í ¼º´ÉÀÇ Æò°¡¸¦ ÇÒ¼ö ÀÖ´Â ±âȸ°¡ ¾ðÁ¨°¡ ÁÖ¾îÁ³À¸¸é ÁÁ°Ú±º¿ä. == Stack(Process)ÀÇ °ü¸®¿ä¼Ò == == ¿¹Á¦ == ¾Æ·¡ÀÇ ¿¹Á¦ ¼Ò½º´Â ½ÇÁ¦ ÇÊÀÚ°¡ ¸¸µé°í ÀÖ´Â ¿î¿µÃ¼Á¦ÀÇ ÀϺθ¦ ¹ßÃéÇÑ°ÍÀÔ´Ï´Ù. ¹ßÃéÇϸ鼭 ¾à°£ÀÇ ºÒÇÊ¿äÇÑ ºÎºÐ°ú ³ª¸§´ë·ÎÀÇ ÁÖ¿ä ¼Ò½º´Â ¹ßÃéÇÏÁö ¾Ê¾Ò½À´Ï´Ù. Â÷ÈÄ¿¡´Â ¿ÏÀüÇÑ Thread¿¹Á¦¸¦ °ø°³Çϵµ·Ï ³ë·ÂÇÏ°Ú½À´Ï´Ù. ÇÏÁö¸¸ Çö½ÃÁ¡¿¡¼­´Â ÀÌ ÀÌ»óÀÇ ¼Ò½º´Â °ø°³ÇÏÁö ¾ÊÀ» ¹æħÀÔ´Ï´Ù. {{{#!vim c /* Copyright (c) Information Equipment co.,LTD. Code by JaeHyuk Cho KOREA MZ Local Thread library v0.0.1b - Simple is best ! */ #if !defined(DEF_SOURCE_thread_c) #define DEF_SOURCE_thread_c "thread.c" typedef struct ts_STACK { void *Stack; int StackSize, StackPointer; }t_STACK; typedef struct ts_THREAD_TASK { struct ts_THREAD_TASK *Next; t_STACK *Stack; unsigned int TaskID, ESP, Tick, Active; void * (*Entry)(void *, void *); void *Argument; }t_THREAD_TASK; typedef struct ts_THREAD { t_THREAD_TASK *Task; t_THREAD_TASK *CurrentTask; unsigned int TaskCount, MakeID; }t_THREAD; t_THREAD *ML_CreateTHREAD(void); t_THREAD *ML_DestroyTHREAD(t_THREAD *s_THREAD); t_THREAD *ML_AddTHREAD(t_THREAD *s_THREAD, void * (*s_ThreadFunction)(void *, void *), void *s_Argument, int s_StackSize); t_THREAD *ML_RunTHREAD(t_THREAD *s_THREAD); int ML_SleepTHREAD(t_THREAD *s_THREAD); t_STACK *ML_CreateSTACK(int s_StackSize); t_STACK *ML_DestroySTACK(t_STACK *s_STACK); int ML_PushSTACK(t_STACK *s_STACK, int s_Value); int ML_PopSTACK(t_STACK *s_STACK, int *s_Value); int ML_SetSTACK(t_STACK *s_STACK, int s_StackPointer); void __ML_ReturnTHREAD__(void); static void *__ML_ManagerTHREAD__(void *s_ThreadHandle, void *s_Argument) { static t_THREAD *sg_THREAD = (t_THREAD *)0; if(sg_THREAD != (t_THREAD *)s_ThreadHandle)sg_THREAD = (t_THREAD *)s_ThreadHandle; ML_SleepTHREAD((t_THREAD *)s_ThreadHandle); if(((t_THREAD *)s_ThreadHandle)->Task->Active == 0)return(s_Argument); t_inline_asm( "__ML_ReturnTHREAD__:\n\t" "pushl $__ML_ReturnTHREAD__\n\t" /* Retry push return address */ ); t_inline_asm( "\n\t" : "=a"(((t_THREAD *)s_ThreadHandle)->CurrentTask->Argument) ); ((t_THREAD *)s_ThreadHandle)->CurrentTask->Active = 0; ML_SleepTHREAD((t_THREAD *)s_ThreadHandle); return(s_Argument); } t_THREAD *ML_CreateTHREAD(void) { t_THREAD *s_Return; s_Return = (t_THREAD *)ML_Alloc(sizeof(t_THREAD)); if(s_Return) { s_Return->Task = s_Return->CurrentTask = (t_THREAD_TASK *)0; s_Return->TaskCount = s_Return->MakeID = 0u; s_Return = ML_AddTHREAD(s_Return, __ML_ManagerTHREAD__, (void *)0, (4 << 10)); } return(s_Return); } t_THREAD *ML_DestroyTHREAD(t_THREAD *s_THREAD) { t_THREAD_TASK *s_THREAD_TASK; if(s_THREAD) { while(s_THREAD->Task && s_THREAD->TaskCount--) { s_THREAD_TASK = s_THREAD->Task; s_THREAD->Task = s_THREAD->Task->Next; if(s_THREAD_TASK->Stack)(void)ML_DestroySTACK(s_THREAD_TASK->Stack); (void)ML_Free(s_THREAD_TASK); } (void)ML_Free(s_THREAD); s_THREAD = (t_THREAD *)0; } return(s_THREAD); } t_THREAD *ML_AddTHREAD(t_THREAD *s_THREAD, void * (*s_ThreadFunction)(void *, void *), void *s_Argument, int s_StackSize) { t_THREAD_TASK *s_THREAD_TASK; if(s_THREAD == (t_THREAD *)0)s_THREAD = ML_CreateTHREAD(); if(s_THREAD) { if(s_THREAD->Task) { s_THREAD_TASK = s_THREAD->Task; while(s_THREAD_TASK->Next && s_THREAD_TASK->Next != s_THREAD->Task)s_THREAD_TASK = s_THREAD_TASK->Next; s_THREAD_TASK->Next = (t_THREAD_TASK *)ML_Alloc(sizeof(t_THREAD_TASK)); s_THREAD_TASK = s_THREAD_TASK->Next; if(s_THREAD->CurrentTask == (t_THREAD_TASK *)0)s_THREAD->CurrentTask = s_THREAD->Task; } else s_THREAD->Task = s_THREAD->CurrentTask = s_THREAD_TASK = (t_THREAD_TASK *)ML_Alloc(sizeof(t_THREAD_TASK)); if(s_THREAD_TASK) { if(s_StackSize < ( 4 << 10 ))s_StackSize = ( 4 << 10 ); s_THREAD_TASK->Next = s_THREAD->Task; s_THREAD_TASK->Stack = ML_CreateSTACK(s_StackSize); s_THREAD_TASK->TaskID = (s_THREAD->MakeID++); s_THREAD_TASK->Tick = 0; s_THREAD_TASK->Active = 1; s_THREAD_TASK->Entry = s_ThreadFunction; s_THREAD_TASK->Argument = s_Argument; s_THREAD_TASK->ESP = (unsigned int)s_THREAD_TASK->Stack->Stack + s_THREAD_TASK->Stack->StackPointer; s_THREAD->TaskCount++; } } return(s_THREAD); } t_THREAD *ML_RunTHREAD(t_THREAD *s_THREAD) { struct { unsigned int eax, ebx, ecx, edx, esi, edi, ebp, esp, flags; }s_Register; t_THREAD_TASK *s_THREAD_TASK; unsigned int s_RegisterAddress, s_TempEBX; if(s_THREAD) { if(s_THREAD->Task) { s_RegisterAddress = (unsigned int)(&s_Register); t_inline_asm( "\n\t" "movl %%ebx, %1\n\t" "movl %0, %%ebx\n\t" "movl %%eax, 0(%%ebx)\n\t" "movl %1, %%eax\n\t" "movl %%eax, 4(%%ebx)\n\t" "movl 0(%%ebx), %%eax\n\t" "movl %%ecx, 8(%%ebx)\n\t" "movl %%edx, 12(%%ebx)\n\t" "movl %%esi, 16(%%ebx)\n\t" "movl %%edi, 20(%%ebx)\n\t" "movl %%ebp, 24(%%ebx)\n\t" "movl %%esp, 28(%%ebx)\n\t" "pushfl\n\t" "popl 32(%%ebx)\n\t" "movl 4(%%ebx), %%ebx\n\t" "\n\t" : : "m"(s_RegisterAddress), "m"(s_TempEBX) ); s_THREAD_TASK = s_THREAD->Task; ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.flags); ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.esp); ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.ebp); ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.edi); ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.esi); ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.edx); ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.ecx); ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.ebx); ML_PushSTACK(s_THREAD_TASK->Stack, (int)s_THREAD_TASK->Argument); ML_PushSTACK(s_THREAD_TASK->Stack, (int)s_THREAD); s_THREAD_TASK->ESP = (unsigned int)s_THREAD_TASK->Stack->Stack + s_THREAD_TASK->Stack->StackPointer; s_THREAD_TASK = s_THREAD_TASK->Next; while(s_THREAD_TASK && s_THREAD_TASK != s_THREAD->Task) { ML_PushSTACK(s_THREAD_TASK->Stack, (int)s_THREAD_TASK->Argument); ML_PushSTACK(s_THREAD_TASK->Stack, (int)s_THREAD); ML_PushSTACK(s_THREAD_TASK->Stack, (int)__ML_ReturnTHREAD__); ML_PushSTACK(s_THREAD_TASK->Stack, (int)s_THREAD_TASK->Argument); ML_PushSTACK(s_THREAD_TASK->Stack, (int)s_THREAD); ML_PushSTACK(s_THREAD_TASK->Stack, (int)__ML_ReturnTHREAD__); ML_PushSTACK(s_THREAD_TASK->Stack, (int)s_THREAD_TASK->Entry); /* First swich entry */ ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.flags); ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.ebp); ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.edi); ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.esi); ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.edx); ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.ecx); ML_PushSTACK(s_THREAD_TASK->Stack, s_Register.ebx); s_THREAD_TASK->ESP = (unsigned int)s_THREAD_TASK->Stack->Stack + s_THREAD_TASK->Stack->StackPointer; s_THREAD_TASK = s_THREAD_TASK->Next; } t_inline_asm( "\n\t" "movl %1, %%ecx\n\t" "movl %0, %%ebp\n\t" "movl %%ebp, %%esp\n\t" "call *%%ecx\n\t" "addl $4 + 4, %%esp\n\t" "popl %%ebx\n\t" "popl %%ecx\n\t" "popl %%edx\n\t" "popl %%esi\n\t" "popl %%edi\n\t" "popl %%ebp\n\t" "popl %%eax\n\t" /* Change stack (x86) */ "popfl\n\t" "movl %%eax, %%esp\n\t" "\n\t" : : "m"(s_THREAD->Task->ESP), "m"(s_THREAD->Task->Entry) ); } } return(s_THREAD); } int ML_SleepTHREAD(t_THREAD *s_THREAD) { s_THREAD->CurrentTask->Tick++; t_inline_asm( "\n\t" "movl %%esp, %%eax\n\t" "subl $28, %%eax\n\t" "\n\t" : "=a"(s_THREAD->CurrentTask->ESP) ); do { s_THREAD->CurrentTask = s_THREAD->CurrentTask->Next; if(s_THREAD->CurrentTask == s_THREAD->Task) { if(s_THREAD->Task->Active == 1) { s_THREAD->CurrentTask->Active = 0; continue; } else break; } }while(s_THREAD->CurrentTask->Active == 0); if(s_THREAD->CurrentTask != s_THREAD->Task)s_THREAD->Task->Active = 1; t_inline_asm( "\n\t" "pushfl\n\t" "pushl %%ebp\n\t" "pushl %%edi\n\t" "pushl %%esi\n\t" "pushl %%edx\n\t" "pushl %%ecx\n\t" "pushl %%ebx\n\t" "movl %0, %%esp\n\t" "popl %%ebx\n\t" "popl %%ecx\n\t" "popl %%edx\n\t" "popl %%esi\n\t" "popl %%edi\n\t" "popl %%ebp\n\t" "popfl\n\t" "\n\t" : : "a"(s_THREAD->CurrentTask->ESP) ); return(1); } t_STACK *ML_CreateSTACK(int s_StackSize) { t_STACK *s_Return; if(s_StackSize < (4 << 10))s_StackSize = (4 << 10); s_Return = (t_STACK *)ML_Alloc(sizeof(t_STACK)); if(s_Return) { s_Return->Stack = (void *)ML_Alloc(s_StackSize); s_Return->StackSize = s_Return->StackPointer = s_StackSize; } return(s_Return); } t_STACK *ML_DestroySTACK(t_STACK *s_STACK) { if(s_STACK) { if(s_STACK->Stack && s_STACK->StackSize > 0)(void)ML_Free(s_STACK->Stack); (void)ML_Free(s_STACK); s_STACK = (t_STACK *)0; } return(s_STACK); } int ML_PushSTACK(t_STACK *s_STACK, int s_Value) { if(s_STACK) { if(s_STACK->Stack && s_STACK->StackSize >= sizeof(s_Value) && s_STACK->StackPointer >= sizeof(s_Value)) { s_STACK->StackPointer -= sizeof(s_Value); ML_PokeDoubleWord(s_STACK->Stack, s_STACK->StackPointer, s_Value); return(s_STACK->StackPointer); } } return(0); } int ML_PopSTACK(t_STACK *s_STACK, int *s_Value) { int s_Return = (-1); if(s_STACK) { if(s_STACK->Stack && s_STACK->StackSize >= sizeof(int) && s_STACK->StackPointer <= (s_STACK->StackSize - sizeof(int))) { s_Return = ML_PeekDoubleWord(s_STACK->Stack, s_STACK->StackPointer); s_STACK->StackPointer += sizeof(int); } } if(s_Value)*(s_Value) = s_Return; return(s_Return); } int ML_SetSTACK(t_STACK *s_STACK, int s_StackPointer) { if(s_STACK) { s_STACK->StackPointer = s_StackPointer; return(s_STACK->StackPointer); } return(0); } #endif /* End of source */ }}} == Âü°íÀÚ·á == * ¾ÆÁ÷Àº ¾øÁö¸¸ ã¾Æº¼²²¿ä~ == ¹®¼­¸¦ ¸¶Ä¡¸é¼­ == ÀÌ ¹®¼­¿¡¼­ Ʋ¸° ºÎºÐÀ̳ª °íÃÄ¾ß ÇҺκÐÀÌ ÀÖÀ¸¸é ²À ¾Ë·ÁÁֽʽÿä. À̱ÛÀÇ ÃÖ±Ù ¹®¼­´Â http://doc.kldp.org ¿¡¼­ ¸¸³ªº¸½Ç¼ö ÀÖ½À´Ï´Ù. ÇÊÀÚÀÇ È¨ÆäÀÌÁö: [http://minzkn.pe.ky] == ÀúÀÛ±Ç == º» ¹®¼­´Â [http://www.gnu.org/licenses/fdl.html GFDL]ÀÇ ¶óÀ̼¾½º¸¦ ±â¹ÝÀ¸·Î ÀÛ¼ºµÇ¾ú°í À¯ÁöµË´Ï´Ù. ----