This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
magicka/deps/odoors/ODInQue.c

444 lines
14 KiB
C
Raw Normal View History

2016-12-03 05:08:50 +00:00
/* OpenDoors Online Software Programming Toolkit
* (C) Copyright 1991 - 1999 by Brian Pirie.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* File: ODInQue.h
*
* Description: OpenDoors input queue management. This input queue is where
* all input events (e.g. keystrokes) from both local and remote
* systems are combined into a single stream.
*
* Revisions: Date Ver Who Change
* ---------------------------------------------------------------
* Nov 16, 1995 6.00 BP Created.
* Nov 17, 1995 6.00 BP Added multithreading support.
* Jan 04, 1996 6.00 BP tODInQueueEvent -> tODInputEvent.
* Jan 30, 1996 6.00 BP Replaced od_yield() with od_sleep().
* Jan 30, 1996 6.00 BP Add semaphore timeout.
* Jan 30, 1996 6.00 BP Add ODInQueueGetNextEvent() timeout.
* Feb 19, 1996 6.00 BP Changed version number to 6.00.
* Mar 03, 1996 6.10 BP Begin version 6.10.
* Aug 10, 2003 6.23 SH *nix support
*/
#define BUILDING_OPENDOORS
#include <stdlib.h>
#include <string.h>
#include "OpenDoor.h"
#include "ODGen.h"
#include "ODInQue.h"
#include "ODPlat.h"
#include "ODKrnl.h"
/* Input queue handle structure. */
typedef struct
{
tODInputEvent *paEvents;
INT nQueueEntries;
INT nInIndex;
INT nOutIndex;
time_t nLastActivityTime;
#ifdef OD_MULTITHREADED
tODSemaphoreHandle hItemCountSemaphore;
tODSemaphoreHandle hAddEventSemaphore;
#endif /* OD_MULTITHREADED */
} tInputQueueInfo;
/* ----------------------------------------------------------------------------
* ODInQueueAlloc()
*
* Allocates a new input queue.
*
* Parameters: phInQueue - Pointer to location where a handle to the
* newly allocated input queue should be
* stored.
*
* nInitialQueueSize - The minimum number of events that the
* input queue should be able to hold.
*
* Return: kODRCSuccess on success, or an error code on failure.
*/
tODResult ODInQueueAlloc(tODInQueueHandle *phInQueue, INT nInitialQueueSize)
{
tInputQueueInfo *pInputQueueInfo = NULL;
tODInputEvent *pInputQueue = NULL;
tODResult Result = kODRCNoMemory;
ASSERT(phInQueue != NULL);
if(phInQueue == NULL) return(kODRCInvalidCall);
/* Attempt to allocate a serial port information structure. */
pInputQueueInfo = malloc(sizeof(tInputQueueInfo));
/* If memory allocation failed, return with failure. */
if(pInputQueueInfo == NULL) goto CleanUp;
/* Initialize semaphore handles to NULL. */
#ifdef OD_MULTITHREADED
pInputQueueInfo->hItemCountSemaphore = NULL;
pInputQueueInfo->hAddEventSemaphore = NULL;
#endif /* OD_MULTITHREADED */
/* Attempt to allocate space for the queue itself. */
pInputQueue = calloc(nInitialQueueSize, sizeof(tODInputEvent));
if(pInputQueue == NULL) goto CleanUp;
/* Create semaphores if this is a multithreaded platform. */
#ifdef OD_MULTITHREADED
if(ODSemaphoreAlloc(&pInputQueueInfo->hItemCountSemaphore, 0,
nInitialQueueSize) != kODRCSuccess)
{
goto CleanUp;
}
if(ODSemaphoreAlloc(&pInputQueueInfo->hAddEventSemaphore, 1, 1)
!= kODRCSuccess)
{
goto CleanUp;
}
#endif /* OD_MULTITHREADED */
/* Initialize input queue information structure. */
pInputQueueInfo->paEvents = pInputQueue;
pInputQueueInfo->nQueueEntries = nInitialQueueSize;
pInputQueueInfo->nInIndex = 0;
pInputQueueInfo->nOutIndex = 0;
/* Convert intut queue information structure pointer to a handle. */
*phInQueue = ODPTR2HANDLE(pInputQueueInfo, tInputQueueInfo);
/* Reset the time of the last activity. */
ODInQueueResetLastActivity(*phInQueue);
Result = kODRCSuccess;
CleanUp:
if(Result != kODRCSuccess)
{
#ifdef OD_MULTITHREADED
if(pInputQueueInfo != NULL
&& pInputQueueInfo->hItemCountSemaphore != NULL)
{
ODSemaphoreFree(pInputQueueInfo->hItemCountSemaphore);
}
if(pInputQueueInfo != NULL
&& pInputQueueInfo->hAddEventSemaphore != NULL)
{
ODSemaphoreFree(pInputQueueInfo->hAddEventSemaphore);
}
#endif /* OD_MULTITHREADED */
if(pInputQueue != NULL) free(pInputQueue);
if(pInputQueueInfo != NULL) free(pInputQueueInfo);
*phInQueue = ODPTR2HANDLE(NULL, tInputQueueInfo);
}
/* Return with the appropriate result code. */
return(Result);
}
/* ----------------------------------------------------------------------------
* ODInQueueFree()
*
* Destroys an input queue that was previously created by ODInQueueAlloc().
*
* Parameters: hInQueue - Handle to the input queue to destroy.
*
* Return: void
*/
void ODInQueueFree(tODInQueueHandle hInQueue)
{
tInputQueueInfo *pInputQueueInfo = ODHANDLE2PTR(hInQueue, tInputQueueInfo);
ASSERT(pInputQueueInfo != NULL);
/* Deallocate semaphores, if appropriate. */
#ifdef OD_MULTITHREADED
ASSERT(pInputQueueInfo->hItemCountSemaphore != NULL);
ODSemaphoreFree(pInputQueueInfo->hItemCountSemaphore);
#endif /* OD_MULTITHREADED */
/* Deallocate the input queue itself. */
ASSERT(pInputQueueInfo->paEvents != NULL);
free(pInputQueueInfo->paEvents);
/* Deallocate port information structure. */
free(pInputQueueInfo);
}
/* ----------------------------------------------------------------------------
* ODInQueueWaiting()
*
* Determines whether or not an event is currently waiting in the input queue.
*
* Parameters: hInQueue - Handle to the input queue to check.
*
* Return: TRUE if there is one or more waiting events, or FALSE if the
* queue is empty.
*/
BOOL ODInQueueWaiting(tODInQueueHandle hInQueue)
{
tInputQueueInfo *pInputQueueInfo = ODHANDLE2PTR(hInQueue, tInputQueueInfo);
BOOL bEventWaiting;
ASSERT(pInputQueueInfo != NULL);
/* There is data waiting in the queue if the in index is not equal to */
/* the out index. */
bEventWaiting = (pInputQueueInfo->nInIndex != pInputQueueInfo->nOutIndex);
return(bEventWaiting);
}
/* ----------------------------------------------------------------------------
* ODInQueueAddEvent()
*
* Adds a new event to the input queue.
*
* Parameters: hInQueue - Handle to the input queue to add an event to.
*
* pEvent - Pointer to the event structure to obtain the
* event information from.
*
* Return: kODRCSuccess on success, or an error code on failure.
*/
tODResult ODInQueueAddEvent(tODInQueueHandle hInQueue,
tODInputEvent *pEvent)
{
tInputQueueInfo *pInputQueueInfo = ODHANDLE2PTR(hInQueue, tInputQueueInfo);
INT nNextInPos;
ASSERT(pInputQueueInfo != NULL);
ASSERT(pEvent != NULL);
if(pInputQueueInfo == NULL || pEvent == NULL) return(kODRCInvalidCall);
/* Serialize access to add event function. */
#ifdef OD_MULTITHREADED
ODSemaphoreDown(pInputQueueInfo->hAddEventSemaphore, OD_NO_TIMEOUT);
#endif /* OD_MULTITHREADED */
/* Reset the time of the last activity. */
ODInQueueResetLastActivity(hInQueue);
/* Determine what the next in index would be after this addition to the */
/* queue. */
nNextInPos = (pInputQueueInfo->nInIndex + 1)
% pInputQueueInfo->nQueueEntries;
/* If the queue is full, then return an out of space error. */
if(nNextInPos == pInputQueueInfo->nOutIndex)
{
/* Allow further access to input queue. */
#ifdef OD_MULTITHREADED
ODSemaphoreUp(pInputQueueInfo->hAddEventSemaphore, 1);
#endif /* OD_MULTITHREADED */
return(kODRCNoMemory);
}
/* Otherwise, add the new event to the input queue. */
memcpy(&pInputQueueInfo->paEvents[pInputQueueInfo->nInIndex], pEvent,
sizeof(tODInputEvent));
/* Update queue in index. */
pInputQueueInfo->nInIndex = nNextInPos;
/* Increment queue items count semaphore. */
#ifdef OD_MULTITHREADED
ODSemaphoreUp(pInputQueueInfo->hItemCountSemaphore, 1);
#endif /* OD_MULTITHREADED */
/* Allow further access to add event function. */
#ifdef OD_MULTITHREADED
ODSemaphoreUp(pInputQueueInfo->hAddEventSemaphore, 1);
#endif /* OD_MULTITHREADED */
return(kODRCSuccess);
}
/* ----------------------------------------------------------------------------
* ODInQueueGetNextEvent()
*
* Obtains the next event from the input queue. If no events are currently
* waiting in the input queue, this function blocks until an item is added
* to the queue, or the maximum wait time is reached.
*
* Parameters: hInQueue - Handle to the input queue to obtain the next event
* from.
*
* pEvent - Pointer to structure to store input event information
* in.
*
* Timeout - Maximum time, in milliseconds, to wait for next input
* event. A value of OD_NO_TIMEOUT causes this function
* to only return when an input event is obtained.
*
* Return: kODRCSuccess on succes, or kODRCTimeout if the maximum wait time
* is exceeded.
*/
tODResult ODInQueueGetNextEvent(tODInQueueHandle hInQueue,
tODInputEvent *pEvent, tODMilliSec Timeout)
{
tInputQueueInfo *pInputQueueInfo = ODHANDLE2PTR(hInQueue, tInputQueueInfo);
ASSERT(pInputQueueInfo != NULL);
ASSERT(pEvent != NULL);
#ifdef OD_MULTITHREADED
/* In multithreaded implementations, we wait for there to be an item in */
/* the queue by decrementing the queue size semaphore. This will cause */
/* this thread to be blocked until an event is added to the queue, if it */
/* is currently empty. */
if(ODSemaphoreDown(pInputQueueInfo->hItemCountSemaphore, Timeout)==kODRCTimeout)
return(kODRCTimeout);
#else /* !OD_MULTITHREADED */
/* In non-multithreaded implementations, we check queue in and out */
/* indicies to determine whether there are any events waiting in the */
/* queue. If the queue is empty we loop, calling od_kernel() to check */
/* for new events and od_yeild() to give more time to other processors */
/* if there is nothing for us to do, until an event is added to the */
/* queue. */
if(pInputQueueInfo->nInIndex == pInputQueueInfo->nOutIndex)
{
tODTimer Timer;
/* If a timeout has been specified, then start timer to keep track */
/* of how long we have been waiting. */
if(Timeout != 0 && Timeout != OD_NO_TIMEOUT)
{
ODTimerStart(&Timer, Timeout);
}
/* As soon as we see that there is nothing in the queue, we do an */
/* od_kernel() call to check for new input. */
CALL_KERNEL_IF_NEEDED();
/* As long as we don't have new input, we loop, yielding to other */
/* processes, and then giving od_kernel() a chance to run. */
while(pInputQueueInfo->nInIndex == pInputQueueInfo->nOutIndex)
{
/* If a timeout has been specified, then ensure that the maximum */
/* wait time has not elapsed. */
if(Timeout != 0 && Timeout != OD_NO_TIMEOUT
&& ODTimerElapsed(&Timer))
{
return(kODRCTimeout);
}
/* Yield the processor to other tasks. */
od_sleep(0);
/* Call od_kernel(). */
CALL_KERNEL_IF_NEEDED();
}
}
#endif /* !OD_MULTITHREADED */
/* Copy next input event from the queue into the caller's structure. */
memcpy(pEvent, &pInputQueueInfo->paEvents[pInputQueueInfo->nOutIndex],
sizeof(tODInputEvent));
/* Move out pointer to the next queue item, wrapping back to the start */
/* of the queue if needed. */
pInputQueueInfo->nOutIndex
= (pInputQueueInfo->nOutIndex + 1) % pInputQueueInfo->nQueueEntries;
/* Now, return with success. */
return(kODRCSuccess);
}
/* ----------------------------------------------------------------------------
* ODInQueueEmpty()
*
* Removes all events from the input queue.
*
* Parameters: hInQueue - Handle to the input queue to be emptied.
*
* Return: void
*/
void ODInQueueEmpty(tODInQueueHandle hInQueue)
{
tODInputEvent InputEvent;
ASSERT(hInQueue != NULL);
/* Remove all items from the queue. */
while(ODInQueueWaiting(hInQueue))
{
ODInQueueGetNextEvent(hInQueue, &InputEvent, OD_NO_TIMEOUT);
}
}
/* ----------------------------------------------------------------------------
* ODInQueueGetLastActivity()
*
* Returns the time of the last input activity. This is the latest of the time
* that the queue was created, the time of the last call to
* ODInQueueAddEvent() on this input queue, and the time of the last call to
* ODInQueueResetLastActivity() on this input queue.
*
* Parameters: hInQueue - Handle to the input queue.
*
* Return: void
*/
time_t ODInQueueGetLastActivity(tODInQueueHandle hInQueue)
{
tInputQueueInfo *pInputQueueInfo = ODHANDLE2PTR(hInQueue, tInputQueueInfo);
ASSERT(pInputQueueInfo != NULL);
/* Returns the last activity time. */
return(pInputQueueInfo->nLastActivityTime);
}
/* ----------------------------------------------------------------------------
* ODInQueueResetLastActivity()
*
* Resets the time of the last input activity to the current time.
*
* Parameters: hInQueue - Handle to the input queue.
*
* Return: void
*/
void ODInQueueResetLastActivity(tODInQueueHandle hInQueue)
{
tInputQueueInfo *pInputQueueInfo = ODHANDLE2PTR(hInQueue, tInputQueueInfo);
ASSERT(pInputQueueInfo != NULL);
/* Resets the last activity time to the current time. */
pInputQueueInfo->nLastActivityTime = time(NULL);
}