/***************************************************************************
 *
 * Definitions for posting, un-posting and checking service requests.
 *
 *	Copyright (C) 1999-2008 Cincom Systems, Inc.
 *
 **************************************************************************/

#ifndef SERVREQUEST_INC
#define SERVREQUEST_INC

#ifndef POLLCOUNT
#define POLLCOUNT 2500
#endif

extern DLUP_IMPORT(int)		interruptPollCount;
extern DLUP_IMPORT(int *)	interruptPoll;

#ifdef ATOMIC_OE_REQUESTS
extern bool anyRequests(void);
#else
/*
 * anyReq and anyAck are read-only exports from stack/services.c
 * that should only be used via the anyRequest macro.
 */
extern DLUP_IMPORT(volatile int) anyReq;
extern DLUP_IMPORT(volatile int) anyAck;
/* Answer if there are any requests. */
#define anyRequests() (anyReq != anyAck)
#endif

/* The first argument to pdWakeup() is either a platform-dependent context
 * descriptor that contains sufficient information to determine the pc of the
 * OE thread, or one of the following values:
 *
 *      ASR_OE_THREAD     an internal call from the OE thread
 *      ASR_FROM_SIGNAL   an internal call from some signal handler
 *      ASR_FROM_THREAD   an internal call from some thread other than the OE.
 */
#define ASR_OE_THREAD	((void *)0)
#define ASR_FROM_SIGNAL	((void *)1)
#define ASR_FROM_THREAD	((void *)2)
#define MAX_ASR ASR_FROM_THREAD


/* needMessageToWakeup is to be set to true whenever OE thread blocks
 * for input (e.g. via poll on unix or WaitMessage on Windows).  It is
 * used by pdWakeup to determine if action must be taken to get the OE
 * out of its blocking wait, e.g. like delivering a wakeup message.  It
 * is also used as an indication that the OE thread is blocking and
 * awaiting input.
 */
extern DLUP_IMPORT(volatile bool) needMessageToWakeup;

extern void asyncSetRequest(unsigned int, void *, bool);
extern void setRequest(unsigned int);
extern void clearRequest(unsigned int);
extern bool anyAsyncRequests(void);
extern void handleRequests(void);
extern void handleAsyncRequests(void);
extern bool isRequested(unsigned int);


/*
 * Event request codes.  These are divided into asynchronous requests and
 * synchronous requests.  Asynchronous requests are those that arise from
 * some source external to Smalltalk asynchronously with Smalltalk execution.
 * These are events like input becomming available or a timer expiring.
 * Synchronous requests are those that arise during Smalltalk execution itself
 * such as a scavenge or a process switch being required.  The distinction is
 * important because the incremental collector in interruptible mode terminates
 * if an asynchronous event occurs, but it ignores synchronous events.
 */
#define MaxRequests					(MaxAsyncRequests+4)
#define RescheduleRequest			(MaxAsyncRequests+3)
#define LowSpaceRequest				(MaxAsyncRequests+2)
#define CompactLargeSpaceRequest	(MaxAsyncRequests+1)
#define ScavengeRequest				(MaxAsyncRequests+0)

#if SIGNALSemaphores
# define MaxAsyncRequests	6
# define SIGNALRequest		5
#else
# define MaxAsyncRequests	5
#endif
#define NBAPIServiceRequest	4
#define ChildDeathRequest	3
#define UserRequest			2
#define TimerRequest		1
/* IORequest, InterruptRequest, and SensorRequest are equivalent; all cause
 * pdSynchronizeInput to be called.
 */
#define IORequest			0
#define InterruptRequest	0
#define SensorRequest		0

#define AsyncRequestsMask ((1 << MaxAsyncRequests) - 1)
#define SyncRequestsMask  (((1 << MaxRequests) - 1) ^ AsyncRequestsMask)

/*
 * Specific response routines.
 */
extern void compactLargeSpaceResponse(void);
extern void lowSpaceResponse(void);
extern void processSwitch(void);
extern void timeExpired(void);
#if SIGNALSemaphores
extern bool registerSignal(int);
# if defined(SIGALRM)
/* Only if #included by a Unix *Sig.c */
extern void signalSIGNALSemaphores(sigset_t *);
# endif
#endif

#endif /* SERVREQUEST_INC */
