Beispiel #1
0
PUBLIC int HTTimer_next (ms_t * pSoonest)
{
    HTList * cur = Timers;
    HTList * last = Timers;
    HTTimer * pres;
    ms_t now = HTGetTimeInMillis();
    int ret = HT_OK;

    /*
    **  Dispatch all timers that have expired
    */
    while (Timers && (pres = (HTTimer *) HTList_nextObject(cur))) {
	if (pres->expires <= now) {
	    if ((ret = Timer_dispatch(cur, last)) != HT_OK) break;
	    cur = last = Timers;
	} else {
	    last = cur;
	}	
    }

    if (pSoonest) {
	/*
	**	First element in Timers is the next to expire.
	*/
	HTList * cur = Timers;	/* for now */
	pres = (HTTimer *) HTList_nextObject(cur);
	*pSoonest = pres ? pres->expires - now : 0;
    }
    return ret;
}
Beispiel #2
0
/* Only responsible for WM_TIMER and WSA_AsyncSelect */    	
PRIVATE LRESULT CALLBACK AsyncWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    WORD event;
    SOCKET sock;
    HTEventType type;
    ms_t now = HTGetTimeInMillis();

    /* timeout stuff */
    if (uMsg == WM_TIMER) {
	HTTimer_dispatch((HTTimer *)wParam);
	return (0);
    }

    if (uMsg != HTwinMsg)	/* not our async message */
    	return (DefWindowProc(hwnd, uMsg, wParam, lParam));

    event = LOWORD(lParam);
    sock = (SOCKET)wParam;
    switch (event) {
    case FD_READ: type = HTEvent_READ; break;
    case FD_WRITE: type = HTEvent_WRITE; break;
    case FD_ACCEPT: type = HTEvent_ACCEPT; break;
    case FD_CONNECT: type = HTEvent_CONNECT; break;
    case FD_OOB: type = HTEvent_OOB; break;
    /* JK: was returning HTEvent_CLOSE before, and this was a source of
       errors, as libwww detects the socket shutdown with a call to recv  */  
    case FD_CLOSE: type = HTEvent_READ; break;
    default: HTDEBUGBREAK("Unknown event %d\n" _ event);
    }
    if (HTEventList_dispatch((int)sock, type, now) != HT_OK)
	HTEndLoop = -1;
    return (0);
}
Beispiel #3
0
PRIVATE ms_t HTMemLog_addTime(void)
{
    char buff[20];
    ms_t ms = HTGetTimeInMillis();
    int len = sprintf(buff, "%lu", ms);
    HTMemLog_add(buff, len);
    return ms;
}
Beispiel #4
0
PRIVATE int HTBufferWriter_write (HTOutputStream * me, const char * buf, int len)
{
    int status;
    while (1) {
	int available = me->data + me->allocated - me->read;

	/* If we have enough buffer space */
	if (len <= available) {
	    int size = 0;
	    memcpy(me->read, buf, len);
	    me->read += len;
        
	    /* If we have accumulated enough data then flush */
	    if ((size = me->read - me->data) > me->growby) {
		me->lastFlushTime = HTGetTimeInMillis();
		status = PUTBLOCK(me->data, size);
		if (status == HT_OK) {
		    me->read = me->data;
		} else {
		    return (status == HT_WOULD_BLOCK) ? HT_OK : HT_ERROR;
		}
	    }
	    return HT_OK;
	} else {

	    /* Fill the existing buffer (if not already) and flush */
	    if (available) {
		memcpy(me->read, buf, available);
		buf += available;
		len -= available;
		me->read += available;
	    }
	    me->lastFlushTime = HTGetTimeInMillis();
	    status = PUTBLOCK(me->data, me->allocated);
	    if (status == HT_OK) {
		me->read = me->data;
	    } else if (status == HT_WOULD_BLOCK) {
		HTBufferWriter_addBuffer(me, len);
		memcpy(me->read, buf, len);
		me->read += len;
		return HT_OK;
	    }
	}
    }
}
Beispiel #5
0
/*
**  This function is only called from either FlushEvent or HTBufferWriter_lazyFlush
**  which means that only the host object or timeout can cause a flush
*/
PRIVATE int HTBufferWriter_flush (HTOutputStream * me)
{
    int status = HT_OK;
    if (me && me->read > me->data) {
	me->lastFlushTime = HTGetTimeInMillis();
        if ((status = PUTBLOCK(me->data, me->read - me->data))==HT_WOULD_BLOCK)
	    return HT_WOULD_BLOCK;
	me->read = me->data;
    }
    return status;
}
Beispiel #6
0
/*
**  Check if the timer object has already expired
*/
PUBLIC BOOL HTTimer_hasTimerExpired (HTTimer * timer)
{
    return (timer && timer->expires <= HTGetTimeInMillis());
}
Beispiel #7
0
PUBLIC HTTimer * HTTimer_new (HTTimer * timer, HTTimerCallback * cbf,
			      void * param, ms_t millis, BOOL relative,
			      BOOL repetitive)
{
    HTList * last;
    HTList * cur;
    ms_t now = HTGetTimeInMillis();
    ms_t expires;
    HTTimer * pres;

    CHECKME(timer);
    expires = millis;
    if (relative)
	expires += now;
    else
	millis = expires-now;

    if (Timers == NULL)
	Timers = HTList_new();

    if (timer) {

	/*	if a timer is specified, it should already exist
	 */
	if ((cur = HTList_elementOf(Timers, (void *)timer, &last)) == NULL) {
	    HTDEBUGBREAK("Timer %p not found\n" _ timer);
	    CLEARME(timer);
	    return NULL;
	}
	HTList_quickRemoveElement(cur, last);
	HTTRACE(THD_TRACE, "Timer....... Found timer %p with callback %p, context %p, and %s timeout %d\n" _ 
		    timer _ cbf _ param _ relative ? "relative" : "absolute" _ millis);
	/* could optimize by sorting from last when ((HTList *)(last->object))->expires < expires (most common case) */
    } else {

	/*	create a new timer
	 */
	if ((timer = (HTTimer *) HT_CALLOC(1, sizeof(HTTimer))) == NULL)
	    HT_OUTOFMEM("HTTimer_new");
	last = Timers;
	HTTRACE(THD_TRACE, "Timer....... Created %s timer %p with callback %p, context %p, and %s timeout %d\n" _ 
		    repetitive ? "repetitive" : "one shot" _ 
		    timer _ cbf _ param _ 
		    relative ? "relative" : "absolute" _ millis);
    }

    /*
    **  Sort new element into list
    */
    for (cur = last; 
	 (pres = (HTTimer *) HTList_nextObject(cur)) != NULL && pres->expires < expires; 
	 last = cur);

    /*
    **  If the expiration is 0 then we still register it but dispatch it immediately.
    */
    if (!millis) HTTRACE(THD_TRACE, "Timer....... Timeout is 0 - expires NOW\n");

    timer->expires = expires;
    timer->cbf = cbf;
    timer->param = param;
    timer->millis = millis;
    timer->relative = relative;
    timer->repetitive = repetitive;
    SETME(timer);

    /*
    **	add to list if timer is new
    */
    cur = HTList_addList(last, (void *)timer);

    /*
    **  Call any platform specific timer handler
    */
    if (SetPlatformTimer) SetPlatformTimer(timer);

    /* Check if the timer object has already expired. If so then dispatch */
    if (timer->expires <= now) Timer_dispatch(cur, last);

    CLEARME(timer);
    return timer;
}
Beispiel #8
0
/*
**  There are now two versions of the event loop. The first is if you want
**  to use async I/O on windows, and the other is if you want to use normal
**  Unix setup with sockets
*/
PUBLIC int HTEventList_loop (HTRequest * theRequest)
{
#ifdef WWW_WIN_ASYNC

    MSG msg;
    int status;
    while (!HTEndLoop && GetMessage(&msg,0,0,0)) {
	    TranslateMessage(&msg);
	    DispatchMessage(&msg);
    }

    status = HTEndLoop;
    
    /* Reset HTEndLoop in case we want to start again */
    HTEndLoop = 0;
    
    return (status == 1 ? HT_OK : HT_ERROR);

#else /* WWW_WIN_ASYNC */

    fd_set treadset, twriteset, texceptset;
    struct timeval waittime, * wt;
    int active_sockets;
    int maxfds;
    ms_t timeout;
    ms_t now;
    SOCKET s;
    int status = HT_OK;

    /* Check that we don't have multiple loops started at once */
    if (HTInLoop) {
	HTTRACE(THD_TRACE, "Event Loop.. Already one loop running - exiting\n");
	return HT_ERROR;
    }
    HTInLoop = YES;

    /* Set up list of events - is kept around until EventOrder_deleteAll */
    if (!EventOrderList)
	EventOrderList = HTList_new();
    else
	EventOrder_clearAll();

    /* Don't leave this loop until we leave the application */
    while (!HTEndLoop) {

        /*
	**  Timeval struct copy needed for linux, as it set the value to the
	**  remaining timeout while exiting the select. (and perhaps for
	**  other OS). Code borrowed from X server.
	*/
	wt = NULL;
	if ((status = HTTimer_next(&timeout)))
	    break;
	if (timeout != 0) {
	    waittime.tv_sec = timeout / MILLI_PER_SECOND;
	    waittime.tv_usec = (timeout % MILLI_PER_SECOND) *
		(1000000 / MILLI_PER_SECOND);
	    wt = &waittime;
	}

	/*
	** Check whether we still have to continue the event loop. It could
	** be that one of the timer handlers ended the loop.
	*/
	if (HTEndLoop) break;

	/*
	**  Now we copy the current active file descriptors to pass them to select.
	*/
        treadset = FdArray[HTEvent_INDEX(HTEvent_READ)];
        twriteset = FdArray[HTEvent_INDEX(HTEvent_WRITE)];
        texceptset = FdArray[HTEvent_INDEX(HTEvent_OOB)];

	/* And also get the max socket value */
        maxfds = MaxSock; 

	HTTRACE(THD_TRACE, "Event Loop.. calling select: maxfds is %d\n" _ maxfds);
#ifdef HTDEBUG
	fd_dump(maxfds, &treadset, &twriteset, &texceptset, wt);
#endif

#ifdef __hpux 
        active_sockets = select(maxfds+1, (int *)&treadset, (int *)&twriteset,
				(int *)&texceptset, wt);
#elif defined(_WINSOCKAPI_)
	/*
	 * [email protected]
	 *
	 * On some WINSOCK versions select() with 3 empty sets and NULL timeout
	 * returns 0 and in some it returns -1.
	 * If 0 is returned in such situation, we will go into an infinite loop
	 * (cause the sets will stay empty forever ...),
	 * so make sure to set the active_sockets = -1 which will take us out 
	 * of the loop.
	 */
	if ((treadset.fd_count || twriteset.fd_count || texceptset.fd_count) 
	    && wt)
	     active_sockets = select(maxfds+1, &treadset, &twriteset,
				     &texceptset, wt);
	else
	     active_sockets = -1;	
#else
        active_sockets = select(maxfds+1, &treadset, &twriteset, &texceptset, wt);
#endif

	now = HTGetTimeInMillis();

	HTTRACE(THD_TRACE, "Event Loop.. select returns %d\n" _ active_sockets);
#ifdef HTDEBUG
	fd_dump(maxfds, &treadset, &twriteset, &texceptset, wt);
#endif

        if (active_sockets == -1) {
#ifdef EINTR
	    if (socerrno == EINTR) {
		/*
		** EINTR     The select() function was interrupted  before  any
		**           of  the  selected  events  occurred and before the
		**           timeout interval expired.
		**
		**           If SA_RESTART has been set  for  the  interrupting
		**           signal,  it  is  implementation-dependent  whether
		**	     select() restarts or returns with EINTR.
		*/
		HTTRACE(THD_TRACE, "Event Loop.. select was interruted - try again\n");
		continue;
	    }
#endif /* EINTR */
#ifdef EBADF
	    if (socerrno == EBADF) {
	        /*
		** EBADF     One or more of the file descriptor sets  specified
		**           a  file  descriptor  that is not a valid open file
		**           descriptor.
		*/
		HTTRACE(THD_TRACE, "Event Loop.. One or more sockets were not through their connect phase - try again\n");
		continue;
	    }
#endif
	    HTTRACE(THD_TRACE, "Event Loop.. select returned error %d\n" _ socerrno);

#ifdef HTDEBUG
	    EventList_dump();
#endif /* HTDEBUG */

	    status = HT_ERROR;
	    break;
        }

	/*
	**  We had a timeout so now we check and see if we have a timeout
	**  handler to call. Let HTTimer_next get it.
	*/ 
	if (active_sockets == 0)
	    continue;

	/* There were active sockets. Determine which fd sets they were in */
	for (s = 0 ; s <= maxfds ; s++) { 
	    if (FD_ISSET(s, &texceptset))
		if ((status = EventOrder_add(s, HTEvent_OOB, now)) != HT_OK)
		    goto stop_loop;
	    if (FD_ISSET(s, &twriteset))
		if ((status = EventOrder_add(s, HTEvent_WRITE, now)) != HT_OK)
		    goto stop_loop;
	    if (FD_ISSET(s, &treadset))
		if ((status = EventOrder_add(s, HTEvent_READ, now)) != HT_OK)
		    goto stop_loop;
	}
	if ((status = EventOrder_executeAndDelete()) != HT_OK) break;
    };

    /* Reset HTEndLoop in case we want to start again */
 stop_loop:
    HTEndLoop = 0;
    HTInLoop = NO;
    return status;
#endif /* !WWW_WIN_ASYNC */
}