live555 中的socket的任务调度分析
1.添加一个socket任务
1 envir().taskScheduler().setBackgroundHandling(socketNum, SOCKET_WRITABLE|SOCKET_EXCEPTION, 2 (TaskScheduler::BackgroundHandlerProc*)&connectionHandler, this);
2.接下来就会把相关参数设置进socket任务集合中去,接下来就是等待任务调度。
fHandlers->assignHandler(socketNum, conditionSet, handlerProc, clientData)
class HandlerSet是一个链表类,里面存在一个成员变量fHandlers,是这个链表的头结点。
assignHandler函数会将socket相关的一些参数,函数指针等封装成一个新节点,插入链表。
3.doEventLoop 是事件循环函数,用于调度事件。
1 void BasicTaskScheduler0::doEventLoop(char* watchVariable) { 2 // Repeatedly loop, handling readble sockets and timed events: 3 while (1) { 4 if (watchVariable != NULL && *watchVariable != 0) break; 5 SingleStep(); 6 } 7 }
4.在SingleStep函数中使用select来监听socket的任务的发生。
1 int selectResult = select(fMaxNumSockets, &readSet, &writeSet, &exceptionSet, &tv_timeToDelay); 2
在SingleStep中使用了一个参数 fLastHandledSocketNum 记录了上次任务发生时该任务在链表中的位置。
a.检测是否上次的任务在任务链表中的某一个位置,如果在就从这个位置开始查找是否发生socket任务。
if (fLastHandledSocketNum >= 0) { while ((handler = iter.next()) != NULL) { if (handler->socketNum == fLastHandledSocketNum) break; } if (handler == NULL) { fLastHandledSocketNum = -1; iter.reset(); // start from the beginning instead } } while ((handler = iter.next()) != NULL) { int sock = handler->socketNum; // alias int resultConditionSet = 0; if (FD_ISSET(sock, &readSet) && FD_ISSET(sock, &fReadSet)/*sanity check*/) resultConditionSet |= SOCKET_READABLE; if (FD_ISSET(sock, &writeSet) && FD_ISSET(sock, &fWriteSet)/*sanity check*/) resultConditionSet |= SOCKET_WRITABLE; if (FD_ISSET(sock, &exceptionSet) && FD_ISSET(sock, &fExceptionSet)/*sanity check*/) resultConditionSet |= SOCKET_EXCEPTION; if ((resultConditionSet&handler->conditionSet) != 0 && handler->handlerProc != NULL) { fLastHandledSocketNum = sock; // Note: we set "fLastHandledSocketNum" before calling the handler, // in case the handler calls "doEventLoop()" reentrantly. (*handler->handlerProc)(handler->clientData, resultConditionSet); break; } }
b. 如果没有任何soket任务发生,于是认为有可能在fLastHandledSocketNum 任务链表位置前面的某一个地方发生了socket任务。接下来就
从链表头开始遍历,查找socket任务的发生。
1 if (handler == NULL && fLastHandledSocketNum >= 0) { 2 // We didn't call a handler, but we didn't get to check all of them, 3 // so try again from the beginning: 4 iter.reset(); 5 while ((handler = iter.next()) != NULL) { 6 int sock = handler->socketNum; // alias 7 int resultConditionSet = 0; 8 if (FD_ISSET(sock, &readSet) && FD_ISSET(sock, &fReadSet)/*sanity check*/) resultConditionSet |= SOCKET_READABLE; 9 if (FD_ISSET(sock, &writeSet) && FD_ISSET(sock, &fWriteSet)/*sanity check*/) resultConditionSet |= SOCKET_WRITABLE; 10 if (FD_ISSET(sock, &exceptionSet) && FD_ISSET(sock, &fExceptionSet)/*sanity check*/) resultConditionSet |= SOCKET_EXCEPTION; 11 if ((resultConditionSet&handler->conditionSet) != 0 && handler->handlerProc != NULL) { 12 fLastHandledSocketNum = sock; 13 // Note: we set "fLastHandledSocketNum" before calling the handler, 14 // in case the handler calls "doEventLoop()" reentrantly. 15 (*handler->handlerProc)(handler->clientData, resultConditionSet); 16 break; 17 } 18 } 19 if (handler == NULL) fLastHandledSocketNum = -1;//because we didn't call a handler 20 }
5.查找到socket任务的socket时,调度相关的函数指针,执行相关函数。同时 fLastHandledSocketNum = sock
1 fLastHandledSocketNum = sock; 2 (*handler->handlerProc)(handler->clientData, resultConditionSet);