andre@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ andre@0: /* This Source Code Form is subject to the terms of the Mozilla Public andre@0: * License, v. 2.0. If a copy of the MPL was not distributed with this andre@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ andre@0: andre@0: #if defined(_PRMWAIT_H) andre@0: #else andre@0: #define _PRMWAIT_H andre@0: andre@0: #include "prio.h" andre@0: #include "prtypes.h" andre@0: #include "prclist.h" andre@0: andre@0: PR_BEGIN_EXTERN_C andre@0: andre@0: /********************************************************************************/ andre@0: /********************************************************************************/ andre@0: /********************************************************************************/ andre@0: /****************************** WARNING ****************************/ andre@0: /********************************************************************************/ andre@0: /**************************** This is work in progress. *************************/ andre@0: /************************** Do not make any assumptions *************************/ andre@0: /************************** about the stability of this *************************/ andre@0: /************************** API or the underlying imple- ************************/ andre@0: /************************** mentation. ************************/ andre@0: /********************************************************************************/ andre@0: /********************************************************************************/ andre@0: andre@0: /* andre@0: ** STRUCTURE: PRWaitGroup andre@0: ** DESCRIPTION: andre@0: ** The client may define several wait groups in order to semantically andre@0: ** tie a collection of file descriptors for a single purpose. This allows andre@0: ** easier dispatching of threads that returned with active file descriptors andre@0: ** from the wait function. andre@0: */ andre@0: typedef struct PRWaitGroup PRWaitGroup; andre@0: andre@0: /* andre@0: ** ENUMERATION: PRMWStatus andre@0: ** DESCRIPTION: andre@0: ** This enumeration is used to indicate the completion status of andre@0: ** a receive wait object. Generally stated, a positive value indicates andre@0: ** that the operation is not yet complete. A zero value indicates andre@0: ** success (similar to PR_SUCCESS) and any negative value is an andre@0: ** indication of failure. The reason for the failure can be retrieved andre@0: ** by calling PR_GetError(). andre@0: ** andre@0: ** PR_MW_PENDING The operation is still pending. None of the other andre@0: ** fields of the object are currently valid. andre@0: ** PR_MW_SUCCESS The operation is complete and it was successful. andre@0: ** PR_MW_FAILURE The operation failed. The reason for the failure andre@0: ** can be retrieved by calling PR_GetError(). andre@0: ** PR_MW_TIMEOUT The amount of time allowed for by the object's andre@0: ** 'timeout' field has expired w/o the operation andre@0: ** otherwise coming to closure. andre@0: ** PR_MW_INTERRUPT The operation was cancelled, either by the client andre@0: ** calling PR_CancelWaitFileDesc() or destroying the andre@0: ** entire wait group (PR_DestroyWaitGroup()). andre@0: */ andre@0: typedef enum PRMWStatus andre@0: { andre@0: PR_MW_PENDING = 1, andre@0: PR_MW_SUCCESS = 0, andre@0: PR_MW_FAILURE = -1, andre@0: PR_MW_TIMEOUT = -2, andre@0: PR_MW_INTERRUPT = -3 andre@0: } PRMWStatus; andre@0: andre@0: /* andre@0: ** STRUCTURE: PRMemoryDescriptor andre@0: ** DESCRIPTION: andre@0: ** THis is a descriptor for an interval of memory. It contains a andre@0: ** pointer to the first byte of that memory and the length (in andre@0: ** bytes) of the interval. andre@0: */ andre@0: typedef struct PRMemoryDescriptor andre@0: { andre@0: void *start; /* pointer to first byte of memory */ andre@0: PRSize length; /* length (in bytes) of memory interval */ andre@0: } PRMemoryDescriptor; andre@0: andre@0: /* andre@0: ** STRUCTURE: PRMWaitClientData andre@0: ** DESCRIPTION: andre@0: ** An opague stucture for which a client MAY give provide a concrete andre@0: ** definition and associate with a receive descriptor. The NSPR runtime andre@0: ** does not manage this field. It is completely up to the client. andre@0: */ andre@0: typedef struct PRMWaitClientData PRMWaitClientData; andre@0: andre@0: /* andre@0: ** STRUCTURE: PRRecvWait andre@0: ** DESCRIPTION: andre@0: ** A receive wait object contains the file descriptor that is subject andre@0: ** to the wait and the amount of time (beginning epoch established andre@0: ** when the object is presented to the runtime) the the channel should andre@0: ** block before abandoning the process. andre@0: ** andre@0: ** The success of the wait operation will be noted in the object's andre@0: ** 'outcome' field. The fields are not valid when the NSPR runtime andre@0: ** is in possession of the object. andre@0: ** andre@0: ** The memory descriptor describes an interval of writable memory andre@0: ** in the caller's address space where data from an initial read andre@0: ** can be placed. The description may indicate a null interval. andre@0: */ andre@0: typedef struct PRRecvWait andre@0: { andre@0: PRCList internal; /* internal runtime linkages */ andre@0: andre@0: PRFileDesc *fd; /* file descriptor associated w/ object */ andre@0: PRMWStatus outcome; /* outcome of the current/last operation */ andre@0: PRIntervalTime timeout; /* time allowed for entire operation */ andre@0: andre@0: PRInt32 bytesRecv; /* number of bytes transferred into buffer */ andre@0: PRMemoryDescriptor buffer; /* where to store first segment of input data */ andre@0: PRMWaitClientData *client; /* pointer to arbitrary client defined data */ andre@0: } PRRecvWait; andre@0: andre@0: /* andre@0: ** STRUCTURE: PRMWaitEnumerator andre@0: ** DESCRIPTION: andre@0: ** An enumeration object is used to store the state of an existing andre@0: ** enumeration over a wait group. The opaque object must be allocated andre@0: ** by the client and the reference presented on each call to the andre@0: ** pseudo-stateless enumerator. The enumeration objects are sharable andre@0: ** only in serial fashion. andre@0: */ andre@0: typedef struct PRMWaitEnumerator PRMWaitEnumerator; andre@0: andre@0: andre@0: /* andre@0: ** FUNCTION: PR_AddWaitFileDesc andre@0: ** DESCRIPTION: andre@0: ** This function will effectively add a file descriptor to the andre@0: ** list of those waiting for network receive. The new descriptor andre@0: ** will be semantically tied to the wait group specified. andre@0: ** andre@0: ** The ownership for the storage pointed to by 'desc' is temporarily andre@0: ** passed over the the NSPR runtime. It will be handed back by the andre@0: ** function PR_WaitRecvReady(). andre@0: ** andre@0: ** INPUTS andre@0: ** group A reference to a PRWaitGroup or NULL. Wait groups are andre@0: ** created by calling PR_CreateWaitGroup() and are used andre@0: ** to semantically group various file descriptors by the andre@0: ** client's application. andre@0: ** desc A reference to a valid PRRecvWait. The object of the andre@0: ** reference must be preserved and not be modified andre@0: ** until its ownership is returned to the client. andre@0: ** RETURN andre@0: ** PRStatus An indication of success. If equal to PR_FAILUE details andre@0: ** of the failure are avaiable via PR_GetError(). andre@0: ** andre@0: ** ERRORS andre@0: ** PR_INVALID_ARGUMENT_ERROR andre@0: ** Invalid 'group' identifier or duplicate 'desc' object. andre@0: ** PR_OUT_OF_MEMORY_ERROR andre@0: ** Insuffient memory for internal data structures. andre@0: ** PR_INVALID_STATE_ERROR andre@0: ** The group is being destroyed. andre@0: */ andre@0: NSPR_API(PRStatus) PR_AddWaitFileDesc(PRWaitGroup *group, PRRecvWait *desc); andre@0: andre@0: /* andre@0: ** FUNCTION: PR_WaitRecvReady andre@0: ** DESCRIPTION: andre@0: ** PR_WaitRecvReady will block the calling thread until one of the andre@0: ** file descriptors that have been added via PR_AddWaitFileDesc is andre@0: ** available for input I/O. andre@0: ** INPUT andre@0: ** group A pointer to a valid PRWaitGroup or NULL (the null andre@0: ** group. The function will block the caller until a andre@0: ** channel from the wait group becomes ready for receive andre@0: ** or there is some sort of error. andre@0: ** RETURN andre@0: ** PRReciveWait andre@0: ** When the caller is resumed it is either returned a andre@0: ** valid pointer to a previously added receive wait or andre@0: ** a NULL. If the latter, the function has terminated andre@0: ** for a reason that can be determined by calling andre@0: ** PR_GetError(). andre@0: ** If a valid pointer is returned, the reference is to the andre@0: ** file descriptor contained in the receive wait object. andre@0: ** The outcome of the wait operation may still fail, and andre@0: ** if it has, that fact will be noted in the object's andre@0: ** outcome field. Details can be retrieved from PR_GetError(). andre@0: ** andre@0: ** ERRORS andre@0: ** PR_INVALID_ARGUMENT_ERROR andre@0: ** The 'group' is not known by the runtime. andre@0: ** PR_PENDING_INTERRUPT_ERROR andre@0: The thread was interrupted. andre@0: ** PR_INVALID_STATE_ERROR andre@0: ** The group is being destroyed. andre@0: */ andre@0: NSPR_API(PRRecvWait*) PR_WaitRecvReady(PRWaitGroup *group); andre@0: andre@0: /* andre@0: ** FUNCTION: PR_CancelWaitFileDesc andre@0: ** DESCRIPTION: andre@0: ** PR_CancelWaitFileDesc is provided as a means for cancelling operations andre@0: ** on objects previously submitted by use of PR_AddWaitFileDesc(). If andre@0: ** the runtime knows of the object, it will be marked as having failed andre@0: ** because it was interrupted (similar to PR_Interrupt()). The first andre@0: ** available thread waiting on the group will be made to return the andre@0: ** PRRecvWait object with the outcome noted. andre@0: ** andre@0: ** INPUTS andre@0: ** group The wait group under which the wait receive object was andre@0: ** added. andre@0: ** desc A pointer to the wait receive object that is to be andre@0: ** cancelled. andre@0: ** RETURN andre@0: ** PRStatus If the wait receive object was located and associated andre@0: ** with the specified wait group, the status returned will andre@0: ** be PR_SUCCESS. There is still a race condition that would andre@0: ** permit the offected object to complete normally, but it andre@0: ** is assured that it will complete in the near future. andre@0: ** If the receive object or wait group are invalid, the andre@0: ** function will return with a status of PR_FAILURE. andre@0: ** andre@0: ** ERRORS andre@0: ** PR_INVALID_ARGUMENT_ERROR andre@0: ** The 'group' argument is not recognized as a valid group. andre@0: ** PR_COLLECTION_EMPTY_ERROR andre@0: ** There are no more receive wait objects in the group's andre@0: ** collection. andre@0: ** PR_INVALID_STATE_ERROR andre@0: ** The group is being destroyed. andre@0: */ andre@0: NSPR_API(PRStatus) PR_CancelWaitFileDesc(PRWaitGroup *group, PRRecvWait *desc); andre@0: andre@0: /* andre@0: ** FUNCTION: PR_CancelWaitGroup andre@0: ** DESCRIPTION: andre@0: ** PR_CancelWaitGroup is provided as a means for cancelling operations andre@0: ** on objects previously submitted by use of PR_AddWaitFileDesc(). Each andre@0: ** successive call will return a pointer to a PRRecvWait object that andre@0: ** was previously registered via PR_AddWaitFileDesc(). If no wait andre@0: ** objects are associated with the wait group, a NULL will be returned. andre@0: ** This function should be called in a loop until a NULL is returned andre@0: ** to reclaim all the wait objects prior to calling PR_DestroyWaitGroup(). andre@0: ** andre@0: ** INPUTS andre@0: ** group The wait group under which the wait receive object was andre@0: ** added. andre@0: ** RETURN andre@0: ** PRRecvWait* If the wait group is valid and at least one receive wait andre@0: ** object is present in the group, that object will be andre@0: ** marked as PR_MW_INTERRUPT'd and removed from the group's andre@0: ** queues. Otherwise a NULL will be returned and the reason andre@0: ** for the NULL may be retrieved by calling PR_GetError(). andre@0: ** andre@0: ** ERRORS andre@0: ** PR_INVALID_ARGUMENT_ERROR andre@0: ** PR_GROUP_EMPTY_ERROR andre@0: */ andre@0: NSPR_API(PRRecvWait*) PR_CancelWaitGroup(PRWaitGroup *group); andre@0: andre@0: /* andre@0: ** FUNCTION: PR_CreateWaitGroup andre@0: ** DESCRIPTION: andre@0: ** A wait group is an opaque object that a client may create in order andre@0: ** to semantically group various wait requests. Each wait group is andre@0: ** unique, including the default wait group (NULL). A wait request andre@0: ** that was added under a wait group will only be serviced by a caller andre@0: ** that specified the same wait group. andre@0: ** andre@0: ** INPUT andre@0: ** size The size of the hash table to be used to contain the andre@0: ** receive wait objects. This is just the initial size. andre@0: ** It will grow as it needs to, but to avoid that hassle andre@0: ** one can suggest a suitable size initially. It should andre@0: ** be ~30% larger than the maximum number of receive wait andre@0: ** objects expected. andre@0: ** RETURN andre@0: ** PRWaitGroup If successful, the function will return a pointer to an andre@0: ** object that was allocated by and owned by the runtime. andre@0: ** The reference remains valid until it is explicitly destroyed andre@0: ** by calling PR_DestroyWaitGroup(). andre@0: ** andre@0: ** ERRORS andre@0: ** PR_OUT_OF_MEMORY_ERROR andre@0: */ andre@0: NSPR_API(PRWaitGroup*) PR_CreateWaitGroup(PRInt32 size); andre@0: andre@0: /* andre@0: ** FUNCTION: PR_DestroyWaitGroup andre@0: ** DESCRIPTION: andre@0: ** Undo the effects of PR_CreateWaitGroup(). Any receive wait operations andre@0: ** on the group will be treated as if the each had been the target of a andre@0: ** PR_CancelWaitFileDesc(). andre@0: ** andre@0: ** INPUT andre@0: ** group Reference to a wait group previously allocated using andre@0: ** PR_CreateWaitGroup(). andre@0: ** RETURN andre@0: ** PRStatus Will be PR_SUCCESS if the wait group was valid and there andre@0: ** are no receive wait objects in that group. Otherwise andre@0: ** will indicate PR_FAILURE. andre@0: ** andre@0: ** ERRORS andre@0: ** PR_INVALID_ARGUMENT_ERROR andre@0: ** The 'group' argument does not reference a known object. andre@0: ** PR_INVALID_STATE_ERROR andre@0: ** The group still contains receive wait objects. andre@0: */ andre@0: NSPR_API(PRStatus) PR_DestroyWaitGroup(PRWaitGroup *group); andre@0: andre@0: /* andre@0: ** FUNCTION: PR_CreateMWaitEnumerator andre@0: ** DESCRIPTION: andre@0: ** The PR_CreateMWaitEnumerator() function returns a reference to an andre@0: ** opaque PRMWaitEnumerator object. The enumerator object is required andre@0: ** as an argument for each successive call in the stateless enumeration andre@0: ** of the indicated wait group. andre@0: ** andre@0: ** group The wait group that the enumeration is intended to andre@0: ** process. It may be be the default wait group (NULL). andre@0: ** RETURN andre@0: ** PRMWaitEnumerator* group andre@0: ** A reference to an object that will be used to store andre@0: ** intermediate state of enumerations. andre@0: ** ERRORS andre@0: ** Errors are indicated by the function returning a NULL. andre@0: ** PR_INVALID_ARGUMENT_ERROR andre@0: ** The 'group' argument does not reference a known object. andre@0: ** PR_OUT_OF_MEMORY_ERROR andre@0: */ andre@0: NSPR_API(PRMWaitEnumerator*) PR_CreateMWaitEnumerator(PRWaitGroup *group); andre@0: andre@0: /* andre@0: ** FUNCTION: PR_DestroyMWaitEnumerator andre@0: ** DESCRIPTION: andre@0: ** Destroys the object created by PR_CreateMWaitEnumerator(). The reference andre@0: ** used as an argument becomes invalid. andre@0: ** andre@0: ** INPUT andre@0: ** PRMWaitEnumerator* enumerator andre@0: ** The PRMWaitEnumerator object to destroy. andre@0: ** RETURN andre@0: ** PRStatus andre@0: ** PR_SUCCESS if successful, PR_FAILURE otherwise. andre@0: ** ERRORS andre@0: ** PR_INVALID_ARGUMENT_ERROR andre@0: ** The enumerator is invalid. andre@0: */ andre@0: NSPR_API(PRStatus) PR_DestroyMWaitEnumerator(PRMWaitEnumerator* enumerator); andre@0: andre@0: /* andre@0: ** FUNCTION: PR_EnumerateWaitGroup andre@0: ** DESCRIPTION: andre@0: ** PR_EnumerateWaitGroup is a thread safe enumerator over a wait group. andre@0: ** Each call to the enumerator must present a valid PRMWaitEnumerator andre@0: ** rererence and a pointer to the "previous" element returned from the andre@0: ** enumeration process or a NULL. andre@0: ** andre@0: ** An enumeration is started by passing a NULL as the "previous" value. andre@0: ** Subsequent calls to the enumerator must pass in the result of the andre@0: ** previous call. The enumeration end is signaled by the runtime returning andre@0: ** a NULL as the result. andre@0: ** andre@0: ** Modifications to the content of the wait group are allowed during andre@0: ** an enumeration. The effect is that the enumeration may have to be andre@0: ** "reset" and that may result in duplicates being returned from the andre@0: ** enumeration. andre@0: ** andre@0: ** An enumeration may be abandoned at any time. The runtime is not andre@0: ** keeping any state, so there are no issues in that regard. andre@0: */ andre@0: NSPR_API(PRRecvWait*) PR_EnumerateWaitGroup( andre@0: PRMWaitEnumerator *enumerator, const PRRecvWait *previous); andre@0: andre@0: PR_END_EXTERN_C andre@0: andre@0: #endif /* defined(_PRMWAIT_H) */ andre@0: andre@0: /* prmwait.h */