miranda-forkthread,forkthread_r分析

与forkthread,forkthread_r对应还有另外一套forkthreadex,forkthreadex_r
不同之处在于前者调用_beginthread来创建线程,后者调用_beginthreadex创建线程,可指定的参数更多一些
基本的思想都是一样的,都是为了当进程正常退出的时候能够安全的结束线程,
下面只分析forkthread和forkthread_r.

/*

Purpose:
 
 A safe version of _beginthread()

Description:

 A new thread is created and the source thread is paused until
 internal code to call MS_SYSTEM_THREAD_PUSH is made in the context
 if the new thread.

 The source thread is then released and then the user supplied
 code is called, when that function returns -- MS_SYSTEM_THREAD_POP
 is called and then the thread returns.

 This insures that Miranda will not exit whilst new threads
 are trying to be born; and the unwind wait stack will unsure
 that Miranda will wait for all created threads to return as well.

Caveats:

 The function must be reimplemented across MT plugins, since thread
 creation depends on CRT which can not be shared.

*/

struct THREAD_WAIT_ENTRY {
 DWORD dwThreadId; // valid if hThread isn't signalled
 HANDLE hThread;
 HINSTANCE hOwner;
};

struct THREAD_WAIT_ENTRY *WaitingThreads=NULL;  //这个变量用于登记所有正在工作的线程
                                                //进程结束的时候需要等待所有这些线程结束
int WaitingThreadsCount=0;                      //正在运行的工作线程的总数

struct FORK_ARG {
 HANDLE hEvent;
 pThreadFunc threadcode;
 pThreadFuncEx threadcodeex;
 void *arg;
};

/
// forkthread - starts a new thread

void __cdecl forkthread_r(void * arg)
{
 struct FORK_ARG * fa = (struct FORK_ARG *) arg;
 void (*callercode)(void*)=fa->threadcode;
 void * cookie=fa->arg;
 CallService(MS_SYSTEM_THREAD_PUSH,0,0);
 SetEvent(fa->hEvent);
 __try {
  callercode(cookie);
 } __finally {
  SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
  CallService(MS_SYSTEM_THREAD_POP,0,0);
 }
 return;
}

unsigned long forkthread (
 void (__cdecl *threadcode)(void*),
 unsigned long stacksize,
 void *arg
)
{
 unsigned long rc;
 struct FORK_ARG fa;
 fa.hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
 fa.threadcode=threadcode;
 fa.arg=arg;
 rc=_beginthread(forkthread_r,stacksize,&fa);
 if ((unsigned long)-1L != rc)
  WaitForSingleObject(fa.hEvent,INFINITE);

 CloseHandle(fa.hEvent);
 return rc;
}

static int ForkThreadService(WPARAM wParam, LPARAM lParam)
{
 return (int)forkthread(( pThreadFunc )wParam, 0, ( void* )lParam );
}


//CallService(MS_SYSTEM_THREAD_PUSH,0,0)都做了什么?
//该函数向WaitingThreads里添加一项,表示有一个线程正在工作,同时设置hThreadQueueEmpty为无信号态,即不空
//一般会在线程开始运行的时候调用该函数进行登记
int UnwindThreadPush(WPARAM wParam,LPARAM lParam)
{
 ResetEvent(hThreadQueueEmpty); // thread list is not empty
 if (WaitForSingleObject(hStackMutex,INFINITE)==WAIT_OBJECT_0)
 {
  HANDLE hThread=0;
  DuplicateHandle(GetCurrentProcess(),GetCurrentThread(),GetCurrentProcess(),&hThread,THREAD_SET_CONTEXT,FALSE,0);
  WaitingThreads=mir_realloc(WaitingThreads,sizeof(struct THREAD_WAIT_ENTRY)*(WaitingThreadsCount+1));
  WaitingThreads[WaitingThreadsCount].hThread=hThread;
  WaitingThreads[WaitingThreadsCount].dwThreadId=GetCurrentThreadId();
  WaitingThreads[WaitingThreadsCount].hOwner=GetInstByAddress( GetCurrentThreadEntryPoint() );
  WaitingThreadsCount++;
#ifdef _DEBUG
  {
   char szBuf[64];
   mir_snprintf(szBuf,SIZEOF(szBuf),"*** pushing thread (%x)/n",GetCurrentThreadId());
   OutputDebugStringA(szBuf);
  }
#endif
  ReleaseMutex(hStackMutex);
 } //if
 return 0;
}


//CallService(MS_SYSTEM_THREAD_POP,0,0)都做了什么?
//该函数从WaitingThreads移除一项,假如WaitingThreads为空,设置hThreadQueueEmpty为信号态
//一般在线程结束以后调用该函数将自己从WaitingThreads移除
int UnwindThreadPop(WPARAM wParam,LPARAM lParam)
{
 if (WaitForSingleObject(hStackMutex,INFINITE)==WAIT_OBJECT_0)
 {
  DWORD dwThreadId=GetCurrentThreadId();
  int j;
  for (j=0;j<WaitingThreadsCount;j++)
        {
   if (WaitingThreads[j].dwThreadId == dwThreadId)
            {
    SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
    CloseHandle(WaitingThreads[j].hThread);
    WaitingThreadsCount--;
    if (j<WaitingThreadsCount)
                    memmove(&WaitingThreads[j],&WaitingThreads[j+1],(WaitingThreadsCount-j) * sizeof(struct THREAD_WAIT_ENTRY));
    if (!WaitingThreadsCount)
    {
     mir_free(WaitingThreads);
     WaitingThreads=NULL;
     WaitingThreadsCount=0;
     ReleaseMutex(hStackMutex);
     SetEvent(hThreadQueueEmpty); // thread list is empty now
     return 0;
    }
                else
                {
     WaitingThreads=mir_realloc(WaitingThreads,sizeof(struct THREAD_WAIT_ENTRY)*WaitingThreadsCount);
    } //if
    ReleaseMutex(hStackMutex);
    return 0;
   } //if
  } //for
  ReleaseMutex(hStackMutex);
 } //if
 return 1;
}

//Miranda退出的时候将检查所有的线程是否结束,否则就等待,
//直到所有的线程都正常结束以后,进程才结束
static int MirandaWaitForMutex(HANDLE hEvent)
{
 for (;;) {
  // will get WAIT_IO_COMPLETE for QueueUserAPC() which isnt a result
  DWORD rc=MsgWaitForMultipleObjectsExWorkaround(1, &hEvent, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE);
  if ( rc == WAIT_OBJECT_0 + 1 ) {
   MSG msg;
   while ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) {
    if ( IsDialogMessage(msg.hwnd, &msg) ) continue;
    TranslateMessage(&msg);
    DispatchMessage(&msg);
   }
  } else if ( rc==WAIT_OBJECT_0 ) {
   // got object
   return 1;
  } else if ( rc==WAIT_ABANDONED_0 || rc == WAIT_FAILED ) return 0;
 }
}


static void UnwindThreadWait(void)
{
 // acquire the list and wake up any alertable threads
 if ( MirandaWaitForMutex(hStackMutex) )
    {
  int j;
  for (j=0;j<WaitingThreadsCount;j++)
        {
            //DummyAPCFunc 实际上什么都不做,只是用来唤醒该线程
            //QueueUserAPC 向处于告警状态的线程投递一个APC, APC进入队列以后,
            //线程将会被唤醒执行APC,同时等待函数返回WAIT_IO_COMPLETION。
   QueueUserAPC(DummyAPCFunc,WaitingThreads[j].hThread, 0);
        }
  ReleaseMutex(hStackMutex);
 }

 // give all unclosed threads 5 seconds to close
    // 如果5s以后线程还没有结束,就强力杀掉线程
 SetTimer( NULL, 0, 5000, KillAllThreads );

 // wait until the thread list is empty
 MirandaWaitForMutex(hThreadQueueEmpty);
}

//强力杀掉所有线程
VOID CALLBACK KillAllThreads(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
 if ( MirandaWaitForMutex( hStackMutex ))
    {
  int j;
  for ( j=0; j < WaitingThreadsCount; j++ )
        {
   char szModuleName[ MAX_PATH ];
   GetModuleFileNameA( WaitingThreads[j].hOwner, szModuleName, sizeof(szModuleName));
   Netlib_Logf( NULL, "Thread %08x was abnormally terminated because module '%s' didn't released it",
    WaitingThreads[j].hThread, szModuleName );
   TerminateThread( WaitingThreads[j].hThread, 9999 );
  }

  if ( WaitingThreadsCount )
        {
   mir_free(WaitingThreads);
   WaitingThreads=NULL;
   WaitingThreadsCount=0;
  }

  ReleaseMutex(hStackMutex);
  SetEvent(hThreadQueueEmpty);
    } 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值