/** * 준비 큐에서 태스크를 제거 */ static TCB* kRemoveTaskFromReadyList( BYTE bAPICID, QWORD qwTaskID ) { TCB* pstTarget; BYTE bPriority; // 태스크 ID가 유효하지 않으면 실패 if( GETTCBOFFSET( qwTaskID ) >= TASK_MAXCOUNT ) { return NULL; } // TCB 풀에서 해당 태스크의 TCB를 찾아 실제로 ID가 일치하는가 확인 pstTarget = &( gs_stTCBPoolManager.pstStartAddress[ GETTCBOFFSET( qwTaskID ) ] ); if( pstTarget->stLink.qwID != qwTaskID ) { return NULL; } // 태스크가 존재하는 준비 리스트에서 태스크 제거 bPriority = GETPRIORITY( pstTarget->qwFlags ); if( bPriority >= TASK_MAXREADYLISTCOUNT ) { return NULL; } pstTarget = kRemoveList( &( gs_vstScheduler[ bAPICID ].vstReadyList[ bPriority ]), qwTaskID ); return pstTarget; }
void* kRemoveListFromTail( LIST* pstList ) { LISTLINK* pstLink; if( pstList->iItemCount == 0 ) { return NULL; } pstLink = (LISTLINK*)pstList->pvTail; return kRemoveList(pstList, pstLink->qwID); }
/** * 리스트의 첫 번째 데이터를 제거하여 반환 */ void* kRemoveListFromHeader( LIST* pstList ) { LISTLINK* pstLink; if( pstList->iItemCount == 0 ) { return NULL; } // 헤더를 제거하고, 반환 pstLink = ( LISTLINK* ) pstList->pvHeader; return kRemoveList( pstList, pstLink->qwID ); }
/** * 유휴 태스크 * 대기 큐에 삭제 대기중인 태스크를 정리 */ void kIdleTask( void ) { TCB* pstTask, * pstChildThread, * pstProcess; QWORD qwLastMeasureTickCount, qwLastSpendTickInIdleTask; QWORD qwCurrentMeasureTickCount, qwCurrentSpendTickInIdleTask; QWORD qwTaskID, qwChildThreadID; int i, iCount; void* pstThreadLink; BYTE bCurrentAPICID; BYTE bProcessAPICID; // 현재 코어의 로컬 APIC ID를 확인 bCurrentAPICID = kGetAPICID(); // 프로세서 사용량 계산을 위해 기준 정보를 저장 qwLastSpendTickInIdleTask = gs_vstScheduler[ bCurrentAPICID ].qwSpendProcessorTimeInIdleTask; qwLastMeasureTickCount = kGetTickCount(); while( 1 ) { // 현재 상태를 저장 qwCurrentMeasureTickCount = kGetTickCount(); qwCurrentSpendTickInIdleTask = gs_vstScheduler[ bCurrentAPICID ].qwSpendProcessorTimeInIdleTask; // 프로세서 사용량을 계산 // 100 - ( 유휴 태스크가 사용한 프로세서 시간 ) * 100 / ( 시스템 전체에서 // 사용한 프로세서 시간 ) if( qwCurrentMeasureTickCount - qwLastMeasureTickCount == 0 ) { gs_vstScheduler[ bCurrentAPICID ].qwProcessorLoad = 0; } else { gs_vstScheduler[ bCurrentAPICID ].qwProcessorLoad = 100 - ( qwCurrentSpendTickInIdleTask - qwLastSpendTickInIdleTask ) * 100 /( qwCurrentMeasureTickCount - qwLastMeasureTickCount ); } // 현재 상태를 이전 상태에 보관 qwLastMeasureTickCount = qwCurrentMeasureTickCount; qwLastSpendTickInIdleTask = qwCurrentSpendTickInIdleTask; // 프로세서의 부하에 따라 쉬게 함 kHaltProcessorByLoad( bCurrentAPICID ); // 대기 큐에 대기중인 태스크가 있으면 태스크를 종료함 if( kGetListCount( &( gs_vstScheduler[ bCurrentAPICID ].stWaitList ) ) > 0 ) { while( 1 ) { // 임계 영역 시작 kLockForSpinLock( &( gs_vstScheduler[ bCurrentAPICID ].stSpinLock ) ); pstTask = kRemoveListFromHeader( &( gs_vstScheduler[ bCurrentAPICID ].stWaitList ) ); // 임계 영역 끝 kUnlockForSpinLock( &( gs_vstScheduler[ bCurrentAPICID ].stSpinLock ) ); if( pstTask == NULL ) { break; } if( pstTask->qwFlags & TASK_FLAGS_PROCESS ) { // 프로세스를 종료할 때 자식 스레드가 존재하면 스레드를 모두 // 종료하고, 다시 자식 스레드 리스트에 삽입 iCount = kGetListCount( &( pstTask->stChildThreadList ) ); for( i = 0 ; i < iCount ; i++ ) { // 임계 영역 시작 kLockForSpinLock( &( gs_vstScheduler[ bCurrentAPICID ].stSpinLock ) ); // 스레드 링크의 어드레스에서 꺼내 스레드를 종료시킴 pstThreadLink = ( TCB* ) kRemoveListFromHeader( &( pstTask->stChildThreadList ) ); if( pstThreadLink == NULL ) { // 임계 영역 끝 kUnlockForSpinLock( &( gs_vstScheduler[ bCurrentAPICID ].stSpinLock ) ); break; } // 자식 스레드 리스트에 연결된 정보는 태스크 자료구조에 있는 // stThreadLink의 시작 어드레스이므로, 태스크 자료구조의 시작 // 어드레스를 구하려면 별도의 계산이 필요함 pstChildThread = GETTCBFROMTHREADLINK( pstThreadLink ); // 다시 자식 스레드 리스트에 삽입하여 해당 스레드가 종료될 때 // 자식 스레드가 프로세스를 찾아 스스로 리스트에서 제거하도록 함 kAddListToTail( &( pstTask->stChildThreadList ), &( pstChildThread->stThreadLink ) ); qwChildThreadID = pstChildThread->stLink.qwID; // 임계 영역 끝 kUnlockForSpinLock( &( gs_vstScheduler[ bCurrentAPICID ].stSpinLock ) ); // 자식 스레드를 찾아서 종료 kEndTask( qwChildThreadID ); } // 아직 자식 스레드가 남아있다면 자식 스레드가 다 종료될 때까지 // 기다려야 하므로 다시 대기 리스트에 삽입 if( kGetListCount( &( pstTask->stChildThreadList ) ) > 0 ) { // 임계 영역 시작 kLockForSpinLock( &( gs_vstScheduler[ bCurrentAPICID ].stSpinLock ) ); kAddListToTail( &( gs_vstScheduler[ bCurrentAPICID ].stWaitList ), pstTask ); // 임계 영역 끝 kUnlockForSpinLock( &( gs_vstScheduler[ bCurrentAPICID ].stSpinLock ) ); continue; } // 프로세스를 종료해야 하므로 할당 받은 메모리 영역을 삭제 else { // 유저 레벨 프로세스라면 메모리를 할당 받았을 것이므로 할당 // 받은 메모리를 삭제 if( pstTask->qwFlags & TASK_FLAGS_USERLEVEL ) { kFreeMemory( pstTask->pvMemoryAddress ); } } } else if( pstTask->qwFlags & TASK_FLAGS_THREAD ) { // 스레드라면 프로세스의 자식 스레드 리스트에서 제거 pstProcess = kGetProcessByThread( pstTask ); if( pstProcess != NULL ) { // 프로세스 ID로 프로세스가 속한 스케줄러의 ID를 찾고 스핀락 잠금 if( kFindSchedulerOfTaskAndLock( pstProcess->stLink.qwID, &bProcessAPICID ) == TRUE ) { kRemoveList( &( pstProcess->stChildThreadList ), pstTask->stLink.qwID ); kUnlockForSpinLock( &( gs_vstScheduler[ bProcessAPICID ].stSpinLock ) ); } } } // 여기까지 왔다면 태스크가 정상적으로 종료된 것이므로, // 태스크 자료구조(TCB)와 스택을 반환 qwTaskID = pstTask->stLink.qwID; // 스택을 반환 kFreeMemory( pstTask->pvStackAddress ); // 태스크 자료구조(TCB)를 반환 kFreeTCB( qwTaskID ); kPrintf( "IDLE: Task ID[0x%q] is completely ended.\n", qwTaskID ); } } kSchedule(); } }
/** * 유휴 태스크 * 대기 큐에 삭제 대기중인 태스크를 정리 */ void kIdleTask( void ) { TCB* pstTask, * pstChildThread, * pstProcess; QWORD qwLastMeasureTickCount, qwLastSpendTickInIdleTask; QWORD qwCurrentMeasureTickCount, qwCurrentSpendTickInIdleTask; int i, iCount; QWORD qwTaskID; void* pstThreadLink; // 프로세서 사용량 계산을 위해 기준 정보를 저장 qwLastSpendTickInIdleTask = gs_stScheduler.qwSpendProcessorTimeInIdleTask; qwLastMeasureTickCount = kGetTickCount(); while( 1 ) { // 현재 상태를 저장 qwCurrentMeasureTickCount = kGetTickCount(); qwCurrentSpendTickInIdleTask = gs_stScheduler.qwSpendProcessorTimeInIdleTask; // 프로세서 사용량을 계산 // 100 - ( 유휴 태스크가 사용한 프로세서 시간 ) * 100 / ( 시스템 전체에서 // 사용한 프로세서 시간 ) if( qwCurrentMeasureTickCount - qwLastMeasureTickCount == 0 ) { gs_stScheduler.qwProcessorLoad = 0; } else { gs_stScheduler.qwProcessorLoad = 100 - ( qwCurrentSpendTickInIdleTask - qwLastSpendTickInIdleTask ) * 100 /( qwCurrentMeasureTickCount - qwLastMeasureTickCount ); } // 현재 상태를 이전 상태에 보관 qwLastMeasureTickCount = qwCurrentMeasureTickCount; qwLastSpendTickInIdleTask = qwCurrentSpendTickInIdleTask; // 프로세서의 부하에 따라 쉬게 함 kHaltProcessorByLoad(); // 대기 큐에 대기중인 태스크가 있으면 태스크를 종료함 if( kGetListCount( &( gs_stScheduler.stWaitList ) ) >= 0 ) { while( 1 ) { // 임계 영역 시작 kLockForSpinLock( &( gs_stScheduler.stSpinLock ) ); pstTask = kRemoveListFromHeader( &( gs_stScheduler.stWaitList ) ); if( pstTask == NULL ) { // 임계 영역 끝 kUnlockForSpinLock( &( gs_stScheduler.stSpinLock ) ); break; } if( pstTask->qwFlags & TASK_FLAGS_PROCESS ) { // 프로세스를 종료할 때 자식 스레드가 존재하면 스레드를 모두 // 종료하고, 다시 자식 스레드 리스트에 삽입 iCount = kGetListCount( &( pstTask->stChildThreadList ) ); for( i = 0 ; i < iCount ; i++ ) { // 스레드 링크의 어드레스에서 꺼내 스레드를 종료시킴 pstThreadLink = ( TCB* ) kRemoveListFromHeader( &( pstTask->stChildThreadList ) ); if( pstThreadLink == NULL ) { break; } // 자식 스레드 리스트에 연결된 정보는 태스크 자료구조에 있는 // stThreadLink의 시작 어드레스이므로, 태스크 자료구조의 시작 // 어드레스를 구하려면 별도의 계산이 필요함 pstChildThread = GETTCBFROMTHREADLINK( pstThreadLink ); // 다시 자식 스레드 리스트에 삽입하여 해당 스레드가 종료될 때 // 자식 스레드가 프로세스를 찾아 스스로 리스트에서 제거하도록 함 kAddListToTail( &( pstTask->stChildThreadList ), &( pstChildThread->stThreadLink ) ); // 자식 스레드를 찾아서 종료 kEndTask( pstChildThread->stLink.qwID ); } // 아직 자식 스레드가 남아있다면 자식 스레드가 다 종료될 때까지 // 기다려야 하므로 다시 대기 리스트에 삽입 if( kGetListCount( &( pstTask->stChildThreadList ) ) > 0 ) { kAddListToTail( &( gs_stScheduler.stWaitList ), pstTask ); // 임계 영역 끝 kUnlockForSpinLock( &( gs_stScheduler.stSpinLock ) ); continue; } // 프로세스를 종료해야 하므로 할당 받은 메모리 영역을 삭제 else { // TODO: 추후에 코드 삽입 } } else if( pstTask->qwFlags & TASK_FLAGS_THREAD ) { // 스레드라면 프로세스의 자식 스레드 리스트에서 제거 pstProcess = kGetProcessByThread( pstTask ); if( pstProcess != NULL ) { kRemoveList( &( pstProcess->stChildThreadList ), pstTask->stLink.qwID ); } } qwTaskID = pstTask->stLink.qwID; kFreeTCB( qwTaskID ); // 임계 영역 끝 kUnlockForSpinLock( &( gs_stScheduler.stSpinLock ) ); kPrintf( "IDLE: Task ID[0x%q] is completely ended.\n", qwTaskID ); } } kSchedule(); } }