blob: c964d6f2029baf64d22af6ef7b9bf1deb3b36ae1 [file] [log] [blame]
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Allows a thread to wait on many sockets at once. The standard usage pattern
// would be for a single I/O thread to:
// 1. Create its own SbSocketWaiter.
// 2. Wait on the SbSocketWaiter, indefinitely if no scheduled tasks, or timed
// if there are scheduled future tasks.
// 3. While waiting, the SbSocketWaiter will call back to service ready
// SbSockets.
// 4. Wake up, if signaled to do so.
// 5. If ready to exit, go to 7.
// 6. Add and remove SbSockets to and from the SbSocketWaiter, and go to 2.
// 7. Destroy its SbSocketWaiter and exit.
//
// If another thread wants to queue immediate or schedule future work on the I/O
// thread, it needs to call SbSocketWaiterWakeUp() on the SbSocketWaiter after
// queuing the work item, or the SbSocketWaiter is not otherwise guaranteed to
// wake up.
#ifndef STARBOARD_SOCKET_WAITER_H_
#define STARBOARD_SOCKET_WAITER_H_
#include "starboard/export.h"
#include "starboard/socket.h"
#include "starboard/time.h"
#include "starboard/types.h"
#ifdef __cplusplus
extern "C" {
#endif
// Private structure representing a waiter which can wait for many sockets at
// once on a single thread.
typedef struct SbSocketWaiterPrivate SbSocketWaiterPrivate;
// A handle to a socket waiter.
typedef SbSocketWaiterPrivate* SbSocketWaiter;
// All the interests that a socket may register for on a waiter.
typedef enum SbSocketWaiterInterest {
// No interests whatsoever.
kSbSocketWaiterInterestNone = 0,
// An interest in or readiness to read from a socket without blocking.
kSbSocketWaiterInterestRead = 1 << 0,
// An interest in or readiness to write to a socket without blocking.
kSbSocketWaiterInterestWrite = 1 << 1,
} SbSocketWaiterInterest;
// Possible reasons why a call to SbSocketWaiterWaitTimed returned.
typedef enum SbSocketWaiterResult {
// The wait didn't block because the waiter was invalid.
kSbSocketWaiterResultInvalid,
// The wait stopped because the timeout expired.
kSbSocketWaiterResultTimedOut,
// The wait stopped because a call to SbSocketWaiterWakeUp was consumed.
kSbSocketWaiterResultWokenUp,
} SbSocketWaiterResult;
// Function pointer for socket waiter callbacks.
typedef void (*SbSocketWaiterCallback)(SbSocketWaiter waiter,
SbSocket socket,
void* context,
int ready_interests);
// Well-defined value for an invalid socket watcher handle.
#define kSbSocketWaiterInvalid ((SbSocketWaiter)NULL)
// Returns whether the given socket handle is valid.
static SB_C_INLINE bool SbSocketWaiterIsValid(SbSocketWaiter watcher) {
return watcher != kSbSocketWaiterInvalid;
}
// Creates a new socket waiter for the current thread. A socket waiter should
// have a 1-1 relationship to a thread that wants to wait for socket
// activity. There is no reason to create multiple waiters for a single thread,
// because the thread can only block on one waiter at a time. The results of two
// threads waiting on the same waiter is undefined (and definitely won't work,
// so don't do it). SbSocketWaiters are not thread-safe, except for the
// SbSocketWaiterWakeUp() function, and don't expect to be modified
// concurrently.
SB_EXPORT SbSocketWaiter SbSocketWaiterCreate();
// Destroys a socket waiter. This will also remove all sockets still registered
// by way of SbSocketWaiterAdd. This function may be called on any thread, but
// only if there is no worry of concurrent access to the waiter.
SB_EXPORT bool SbSocketWaiterDestroy(SbSocketWaiter waiter);
// Adds a new socket to be waited on by the |waiter| with a bitfield of
// |interests|. When the event fires, |callback| will be called with |waiter|,
// |socket|, and |context|, as well as a bitfield of which interests the socket
// is actually ready for. This should only be called on the thread that
// waits on this waiter.
//
// If |socket| is already registered with this or another waiter, the function
// will do nothing and return false. The client must remove the socket and then
// add it back with the new |interests|.
//
// If |socket| is already ready for one or more operations set in the
// |interests| mask, then the callback will be called on the next call to
// SbSocketWaiterWait() or SbSocketWaiterWaitTimed().
//
// If |persistent| is true, then |socket| will stay registered with |waiter|
// until SbSocketWaiterRemove() is called with |waiter| and |socket|. Otherwise,
// |socket| will be removed after the next call to |callback|, even if not all
// registered |interests| became ready.
SB_EXPORT bool SbSocketWaiterAdd(SbSocketWaiter waiter,
SbSocket socket,
void* context,
SbSocketWaiterCallback callback,
int interests,
bool persistent);
// Removes |socket| from |waiter|, previously added with SbSocketWaiterAdd. If
// |socket| wasn't registered with |waiter|, then this does nothing. This should
// only be called on the thread that waits on this waiter.
SB_EXPORT bool SbSocketWaiterRemove(SbSocketWaiter waiter, SbSocket socket);
// Waits on all registered sockets, calling the registered callbacks if and when
// the corresponding sockets become ready for an interested operation. This
// version exits only after SbSocketWaiterWakeUp() is called. This should only
// be called on the thread that waits on this waiter.
SB_EXPORT void SbSocketWaiterWait(SbSocketWaiter waiter);
// Behaves the same as SbSocketWaiterWait(), waking up when
// SbSocketWaiterWakeUp(), but also exits on its own after at least |duration|
// has passed, whichever comes first, returning an indicator of which one
// happened. Note that, as with SbThreadSleep(), it may wait longer than
// |duration|. For example if the timeout expires while a callback is being
// fired. This should only be called on the thread that waits on this waiter.
SB_EXPORT SbSocketWaiterResult SbSocketWaiterWaitTimed(SbSocketWaiter waiter,
SbTime duration);
// Wakes up |waiter| once. Can be called from a SbSocketWaiterCallback to wake
// up its own waiter. Can also be called from another thread at any time, it's
// the only thread-safe waiter function. In either case, the waiter will exit
// the next wait gracefully, first completing any in-progress callback.
//
// For every time this function is called, it will cause the waiter to wake up
// one time. This is true whether the waiter is currently waiting or not. If not
// waiting, it will just take affect immediately the next time the waiter
// waits. The number of wake-ups accumulate and are only consumed by waiting and
// getting woken up. e.g. If you call this function 7 times, then
// SbSocketWaiterWait() and WaitTimed() will not block the next 7 times they are
// called.
SB_EXPORT void SbSocketWaiterWakeUp(SbSocketWaiter waiter);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // STARBOARD_SOCKET_WAITER_H_