|
감사합니다
빌더(TWx) 님이 쓰신 글 :
: 답변:
:
:
:
: 프로그램에서 별도의 쓰레드를 생성하지 않는 프로그램이라고 할지라도...
: 멀티 쓰레드를 지원하는 OS에서는 커널 로더가 기본적인 쓰레드인 'main thread'는 항상 생성하게 됩니다.
: 모든 프로세스는 적어도 하나 이상의 쓰레드는 갖고 있는 셈이죠.
:
: 'main thread'에서 입력을 받고, 'Worker Thread'를 생성해서 백그라운드로 MP3 파일을 디코딩해서 음악을 플레이하는
: 어떤 프로그램이 있다고 가정해 봅시다.
:
: 플레이를 Pause 버튼을 눌러서 'Worker Thread'가 Suspend 상태가 되었다고 해서... 프로그램 자체도
: Suspend 상태가 되는 것은 아니지요. 단지 워커 쓰레드만 서스펜드 상태가 되었을 뿐, 메인 쓰레드는 키보드 입력을 받고 있으니.
: 프로그램 자체는 Suspend 상태가 아닙니다.
:
:
: NtResumeProcess()를 이용하는 한...
:
: NtQuerySystemInformation()로 받은 쓰레드 리스트를 갖고...
: 순회하면서 쓰레드 개별적으로 Suspend 샹태를 일일히 체크할 필요가 전혀 없습니다.
:
: 어떤 프로세스의 쓰레드들을 Resume 해주는 건 NtResumeProcess() 내부에서 알아서 처리해주니까...
: 쓰레드 리스트의 가장 첫번째 요소인 'main thread'의 Suspend 상태만 체크하면 됩니다. (ThreadList[0])
:
: 다만 이때 주의 할 것은...
:
: 메모리를 할당해서 NtQuerySystemInformation()를 호출해서 얻은 데이타는 NtResumeProcess()를 호출하기 전에
: 얻은 복사본이란 것을 주의 해야 합니다.
:
: 따라서, 프로세스가 Suspend된 상태에서 NtResumeProcess()를 호출하면 커널 내부 자료구조가 변경되므로...
: 변경이 반영된 쓰레드 상태를 체크하기 위해선 NtQuerySystemInformation()을 다시 호출해서... 변경된 쓰레드 상태 값을
: 다시 복사해 와서 체크하는 구조로 로직을 작성해야 합니다. (ThreadList[0], 메인 쓰레드만 Suspend 상태 체크)
:
: 덧붙여서...
:
: 인터넷 익스플로어의 경우...
:
: IE 웹브라우저를 열면 iexplore.exe 라는 프로세스 이름을 갖는 프로세스들이 몇개 생생될 수도 있는데...
: 이런 경우는 생성된 프로세스들을 같이 일괄적으로 Resume하거나 Suspend 해야... 웹브라우저 프로그램이 전체적으로
: Resume/Suspend 되는 결과를 얻을 수 있습니다.
:
:
:
:
: 님이 쓰신 글 :
: : waitreason 값을 5와 대조해서
: :
: : 5면 계속 Resume 을 주도록 만들었는데
: :
: : 간혹 쓰레드 중에 waitreason 값이 기본이 5인것인지 어쩐것인진 몰라도
: :
: : 리줌을 천번 줘도 계속 5의 값을 유지하고 있는 녀석이 있네요
: :
: : 실제로 프로그램은 Resume 되서 잘 움직이고 있구요
: :
: : 해당 부분 코드는 아래와 같습니다.
: :
: :
: :
: : for(int i = 0; i < infoP->ThreadCount ; i++)
: : {
: : while (infoP->Threads[i].WaitReason == 5)
: : {
: : DV(("[IDFS] %s Resume",StrProcess));
: : NtResumeProcess(ProcessHandle);
: : if (pBuffer) HeapFree(GetProcessHeap(), NULL, pBuffer);
: : goto Re;
: : }
: : }
: : 얼덜 님이 쓰신 글 :
: : : 감사합니다!! 덕분에 좋은걸 많이 알아가네요
: : :
: : :
: : : 빌더(TWx) 님이 쓰신 글 :
: : : : 얼덜 님이 쓰신 글 :
: : : : : 안녕하세요 프로세스를 서스펜드 하다가
: : : : :
: : : : : 의문점이 생겨서 질문드립니다.
: : : : :
: : : : : 예전에는 프로세스랑 쓰레드 둘다 스냅샷을 찍어서 pid 동일한거 찾은다음
: : : : :
: : : : : 쓰레드를 SuspendThread 시켰는데 이 방식이 불안정(?) 하다는 말을 들어서
: : : : :
: : : : : NtSuspendProcess 함수를 써서 서스펜드 시키게 됬습니다
: : : : :
: : : : : 문제는 기존 함수였던 SuspendThread / ResumeThread 함수들은 리턴값으로 서스펜드 카운트를 반환해서
: : : : :
: : : : : 몇번 서스펜드 명령이 있었는지를 보고 그만큼 Resume 을줬었는데
: : : : :
: : : : : NtSuspendProcess 함수는 그런걸 반환안하더라구요 그냥 반환값 무조건 0;
: : : : :
: : : : : 그래서인지 서스펜드를 여러번 시켜서 서스펜드 카운트는 쌓였는데 Resume 은 한번만 줘서
: : : : :
: : : : : 프로그램이 정상작동을 하지 않는등의 문제가 생깁니다.
: : : : :
: : : : : NtSuspendProcess 함수로 서스펜드 카운트를 받는 방법이 있을까요?
: : : : :
: : : : : 그리고 NtSuspendProcess 랑 SuspendThread 랑 무슨 차이가 있나요?
: : : : :
: : : :
: : : :
: : : : 답변:
: : : :
: : : :
: : : :
: : : : NtSuspendProcess()는 리턴값으로 NT_STATUS 를 사용하므로... 성공하면 0 값을 리턴하게 됩니다.
: : : : 커널 내부 자료구조에서 카운트를 유지하고 있어서 NtSuspendProcess()를 여러번 호출했다면 프로세스를 Resume 시키기
: : : : 위해선 NtSuspendProcess()를 호출한 횟수 만큼 NtResumeProcess()를 호출해줘야 합니다.
: : : :
: : : : 그에 반해서...
: : : : NtResumeProcess()는 여러번 호출해도 상관 없습니다. NtSuspendProcess()를 호출한 수 만큼 NtResumeProcess()를
: : : : 호출하면 프로세스가 Resume 상태가 되고, 그 후에 또 다시 NtResumeProcess()를 호출해도 카운트 되는 것은 없다는 거죠.
: : : :
: : : : 카운트 값은 커널 내부 자료구조에서 갖고 있으므로...
: : : : 위 두개의 API를 이용해서 처리할 경우.. 타겟 프로세스 상태가 Suspend상태인지 아닌지를 알아내서 Suspend 가 풀릴 때 까지
: : : : NtResumeProcess()를 계속 호출하는 구조로 로직을 구성해야 합니다.
: : : :
: : : : 타겟 프로세스의 Resume/Suspended 상태는 NtQuerySystemInformation()를 이용해서 알아 낼 수 있습니다.
: : : : 어떤 프로세스의 SYSTEM_THREAD 라는 자료구조의 WaitReason 필드 값이 '5'이면 Suspended 상태 입니다.
: : : :
: : : :
: : : : SuspendThread()를 이용하는 것 보다 NtSuspendProcess()을 이용하는 게 유리한 것은...
: : : :
: : : : 하나의 프로세스는 여러개의 쓰레드를 가질 수 있고, 각기의 쓰레드를 개별적으로 Resume/Suspended 처리를 하게 되면
: : : : 쓰레드 간의 종속관계로 인해서 문제가 발생할 수도 있기 때문 입니다. 잘못하면 데드락 상황이 발생할 수도 있고요.
: : : :
: : : :
: : : : NtQuerySystemInformation(), NtSuspendProcess(), NtResumeProcess() 등의 함수는 Undocumented API 이지만...
: : : : XP 이후부터 현재의 Windows 10 에 이르기 까지 계속 사용되고 있습니다. 커널 변경에 따라서 함수의 내부 Implementation이
: : : : 바뀔 수는 있어도... Win32 레이어가 존재하는 한... 이 API들이 사라질 가능성은 ... 전혀 없다고 봐도 무방 하지요.
: : : :
: : : : 시스템 유틸리티 프로그램을 만들 때... 상당히 자주 사용되는 API이기도 합니다.(MS에서도 자신들이 만든 프로그램에서 자주
: : : : 사용하기도 합니다.) Undocumented API라고 해서 꺼릴 필요는 없다는 겁니다.
: : : :
: : : :
: : : :
: : : :
|