diff options
Diffstat (limited to 'pjlib/include/pj/ioqueue.h')
-rw-r--r-- | pjlib/include/pj/ioqueue.h | 1330 |
1 files changed, 665 insertions, 665 deletions
diff --git a/pjlib/include/pj/ioqueue.h b/pjlib/include/pj/ioqueue.h index 26484cad..86a5309f 100644 --- a/pjlib/include/pj/ioqueue.h +++ b/pjlib/include/pj/ioqueue.h @@ -1,665 +1,665 @@ -/* $Id$
- */
-/*
- * Copyright (C)2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef __PJ_IOQUEUE_H__
-#define __PJ_IOQUEUE_H__
-
-/**
- * @file ioqueue.h
- * @brief I/O Dispatching Mechanism
- */
-
-#include <pj/types.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJ_IO Input/Output
- * @brief Input/Output
- * @ingroup PJ_OS
- *
- * This section contains API building blocks to perform network I/O and
- * communications. If provides:
- * - @ref PJ_SOCK
- *\n
- * A highly portable socket abstraction, runs on all kind of
- * network APIs such as standard BSD socket, Windows socket, Linux
- * \b kernel socket, PalmOS networking API, etc.
- *
- * - @ref pj_addr_resolve
- *\n
- * Portable address resolution, which implements #pj_gethostbyname().
- *
- * - @ref PJ_SOCK_SELECT
- *\n
- * A portable \a select() like API (#pj_sock_select()) which can be
- * implemented with various back-ends.
- *
- * - @ref PJ_IOQUEUE
- *\n
- * Framework for dispatching network events.
- *
- * For more information see the modules below.
- */
-
-/**
- * @defgroup PJ_IOQUEUE I/O Event Dispatching Queue
- * @ingroup PJ_IO
- * @{
- *
- * I/O Queue provides API for performing asynchronous I/O operations. It
- * conforms to proactor pattern, which allows application to submit an
- * asynchronous operation and to be notified later when the operation has
- * completed.
- *
- * The I/O Queue can work on both socket and file descriptors. For
- * asynchronous file operations however, one must make sure that the correct
- * file I/O back-end is used, because not all file I/O back-end can be
- * used with the ioqueue. Please see \ref PJ_FILE_IO for more details.
- *
- * The framework works natively in platforms where asynchronous operation API
- * exists, such as in Windows NT with IoCompletionPort/IOCP. In other
- * platforms, the I/O queue abstracts the operating system's event poll API
- * to provide semantics similar to IoCompletionPort with minimal penalties
- * (i.e. per ioqueue and per handle mutex protection).
- *
- * The I/O queue provides more than just unified abstraction. It also:
- * - makes sure that the operation uses the most effective way to utilize
- * the underlying mechanism, to achieve the maximum theoritical
- * throughput possible on a given platform.
- * - choose the most efficient mechanism for event polling on a given
- * platform.
- *
- * Currently, the I/O Queue is implemented using:
- * - <tt><b>select()</b></tt>, as the common denominator, but the least
- * efficient. Also the number of descriptor is limited to
- * \c PJ_IOQUEUE_MAX_HANDLES (which by default is 64).
- * - <tt><b>/dev/epoll</b></tt> on Linux (user mode and kernel mode),
- * a much faster replacement for select() on Linux (and more importantly
- * doesn't have limitation on number of descriptors).
- * - <b>I/O Completion ports</b> on Windows NT/2000/XP, which is the most
- * efficient way to dispatch events in Windows NT based OSes, and most
- * importantly, it doesn't have the limit on how many handles to monitor.
- * And it works with files (not only sockets) as well.
- *
- *
- * \section pj_ioqueue_concurrency_sec Concurrency Rules
- *
- * The items below describe rules that must be obeyed when using the I/O
- * queue, with regard to concurrency:
- * - simultaneous operations (by different threads) to different key is safe.
- * - simultaneous operations to the same key is also safe, except
- * <b>unregistration</b>, which is described below.
- * - <b>care must be taken when unregistering a key</b> from the
- * ioqueue. Application must take care that when one thread is issuing
- * an unregistration, other thread is not simultaneously invoking an
- * operation <b>to the same key</b>.
- *\n
- * This happens because the ioqueue functions are working with a pointer
- * to the key, and there is a possible race condition where the pointer
- * has been rendered invalid by other threads before the ioqueue has a
- * chance to acquire mutex on it.
- *
- * \section pj_ioqeuue_examples_sec Examples
- *
- * For some examples on how to use the I/O Queue, please see:
- *
- * - \ref page_pjlib_ioqueue_tcp_test
- * - \ref page_pjlib_ioqueue_udp_test
- * - \ref page_pjlib_ioqueue_perf_test
- */
-
-
-/**
- * This structure describes operation specific key to be submitted to
- * I/O Queue when performing the asynchronous operation. This key will
- * be returned to the application when completion callback is called.
- *
- * Application normally wants to attach it's specific data in the
- * \c user_data field so that it can keep track of which operation has
- * completed when the callback is called. Alternatively, application can
- * also extend this struct to include its data, because the pointer that
- * is returned in the completion callback will be exactly the same as
- * the pointer supplied when the asynchronous function is called.
- */
-typedef struct pj_ioqueue_op_key_t
-{
- void *internal__[32]; /**< Internal I/O Queue data. */
- void *user_data; /**< Application data. */
-} pj_ioqueue_op_key_t;
-
-/**
- * This structure describes the callbacks to be called when I/O operation
- * completes.
- */
-typedef struct pj_ioqueue_callback
-{
- /**
- * This callback is called when #pj_ioqueue_recv or #pj_ioqueue_recvfrom
- * completes.
- *
- * @param key The key.
- * @param op_key Operation key.
- * @param bytes_read >= 0 to indicate the amount of data read,
- * otherwise negative value containing the error
- * code. To obtain the pj_status_t error code, use
- * (pj_status_t code = -bytes_read).
- */
- void (*on_read_complete)(pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- pj_ssize_t bytes_read);
-
- /**
- * This callback is called when #pj_ioqueue_write or #pj_ioqueue_sendto
- * completes.
- *
- * @param key The key.
- * @param op_key Operation key.
- * @param bytes_sent >= 0 to indicate the amount of data written,
- * otherwise negative value containing the error
- * code. To obtain the pj_status_t error code, use
- * (pj_status_t code = -bytes_sent).
- */
- void (*on_write_complete)(pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- pj_ssize_t bytes_sent);
-
- /**
- * This callback is called when #pj_ioqueue_accept completes.
- *
- * @param key The key.
- * @param op_key Operation key.
- * @param sock Newly connected socket.
- * @param status Zero if the operation completes successfully.
- */
- void (*on_accept_complete)(pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- pj_sock_t sock,
- pj_status_t status);
-
- /**
- * This callback is called when #pj_ioqueue_connect completes.
- *
- * @param key The key.
- * @param status PJ_SUCCESS if the operation completes successfully.
- */
- void (*on_connect_complete)(pj_ioqueue_key_t *key,
- pj_status_t status);
-} pj_ioqueue_callback;
-
-
-/**
- * Types of pending I/O Queue operation. This enumeration is only used
- * internally within the ioqueue.
- */
-typedef enum pj_ioqueue_operation_e
-{
- PJ_IOQUEUE_OP_NONE = 0, /**< No operation. */
- PJ_IOQUEUE_OP_READ = 1, /**< read() operation. */
- PJ_IOQUEUE_OP_RECV = 2, /**< recv() operation. */
- PJ_IOQUEUE_OP_RECV_FROM = 4, /**< recvfrom() operation. */
- PJ_IOQUEUE_OP_WRITE = 8, /**< write() operation. */
- PJ_IOQUEUE_OP_SEND = 16, /**< send() operation. */
- PJ_IOQUEUE_OP_SEND_TO = 32, /**< sendto() operation. */
-#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
- PJ_IOQUEUE_OP_ACCEPT = 64, /**< accept() operation. */
- PJ_IOQUEUE_OP_CONNECT = 128, /**< connect() operation. */
-#endif /* PJ_HAS_TCP */
-} pj_ioqueue_operation_e;
-
-
-/**
- * This macro specifies the maximum number of events that can be
- * processed by the ioqueue on a single poll cycle, on implementation
- * that supports it. The value is only meaningfull when specified
- * during PJLIB build.
- */
-#ifndef PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL
-# define PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL (16)
-#endif
-
-/**
- * When this flag is specified in ioqueue's recv() or send() operations,
- * the ioqueue will always mark the operation as asynchronous.
- */
-#define PJ_IOQUEUE_ALWAYS_ASYNC ((pj_uint32_t)1 << (pj_uint32_t)31)
-
-/**
- * Return the name of the ioqueue implementation.
- *
- * @return Implementation name.
- */
-PJ_DECL(const char*) pj_ioqueue_name(void);
-
-
-/**
- * Create a new I/O Queue framework.
- *
- * @param pool The pool to allocate the I/O queue structure.
- * @param max_fd The maximum number of handles to be supported, which
- * should not exceed PJ_IOQUEUE_MAX_HANDLES.
- * @param ioqueue Pointer to hold the newly created I/O Queue.
- *
- * @return PJ_SUCCESS on success.
- */
-PJ_DECL(pj_status_t) pj_ioqueue_create( pj_pool_t *pool,
- pj_size_t max_fd,
- pj_ioqueue_t **ioqueue);
-
-/**
- * Destroy the I/O queue.
- *
- * @param ioque The I/O Queue to be destroyed.
- *
- * @return PJ_SUCCESS if success.
- */
-PJ_DECL(pj_status_t) pj_ioqueue_destroy( pj_ioqueue_t *ioque );
-
-/**
- * Set the lock object to be used by the I/O Queue. This function can only
- * be called right after the I/O queue is created, before any handle is
- * registered to the I/O queue.
- *
- * Initially the I/O queue is created with non-recursive mutex protection.
- * Applications can supply alternative lock to be used by calling this
- * function.
- *
- * @param ioque The ioqueue instance.
- * @param lock The lock to be used by the ioqueue.
- * @param auto_delete In non-zero, the lock will be deleted by the ioqueue.
- *
- * @return PJ_SUCCESS or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioque,
- pj_lock_t *lock,
- pj_bool_t auto_delete );
-
-/**
- * Register a socket to the I/O queue framework.
- * When a socket is registered to the IOQueue, it may be modified to use
- * non-blocking IO. If it is modified, there is no guarantee that this
- * modification will be restored after the socket is unregistered.
- *
- * @param pool To allocate the resource for the specified handle,
- * which must be valid until the handle/key is unregistered
- * from I/O Queue.
- * @param ioque The I/O Queue.
- * @param sock The socket.
- * @param user_data User data to be associated with the key, which can be
- * retrieved later.
- * @param cb Callback to be called when I/O operation completes.
- * @param key Pointer to receive the key to be associated with this
- * socket. Subsequent I/O queue operation will need this
- * key.
- *
- * @return PJ_SUCCESS on success, or the error code.
- */
-PJ_DECL(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
- pj_ioqueue_t *ioque,
- pj_sock_t sock,
- void *user_data,
- const pj_ioqueue_callback *cb,
- pj_ioqueue_key_t **key );
-
-/**
- * Unregister from the I/O Queue framework. Caller must make sure that
- * the key doesn't have any pending operations before calling this function,
- * by calling #pj_ioqueue_is_pending() for all previously submitted
- * operations except asynchronous connect, and if necessary call
- * #pj_ioqueue_post_completion() to cancel the pending operations.
- *
- * Note that asynchronous connect operation will automatically be
- * cancelled during the unregistration.
- *
- * @param key The key that was previously obtained from registration.
- *
- * @return PJ_SUCCESS on success or the error code.
- *
- * @see pj_ioqueue_is_pending
- */
-PJ_DECL(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key );
-
-
-/**
- * Get user data associated with an ioqueue key.
- *
- * @param key The key that was previously obtained from registration.
- *
- * @return The user data associated with the descriptor, or NULL
- * on error or if no data is associated with the key during
- * registration.
- */
-PJ_DECL(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key );
-
-/**
- * Set or change the user data to be associated with the file descriptor or
- * handle or socket descriptor.
- *
- * @param key The key that was previously obtained from registration.
- * @param user_data User data to be associated with the descriptor.
- * @param old_data Optional parameter to retrieve the old user data.
- *
- * @return PJ_SUCCESS on success or the error code.
- */
-PJ_DECL(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key,
- void *user_data,
- void **old_data);
-
-
-/**
- * Initialize operation key.
- *
- * @param op_key The operation key to be initialied.
- * @param size The size of the operation key.
- */
-PJ_DECL(void) pj_ioqueue_op_key_init( pj_ioqueue_op_key_t *op_key,
- pj_size_t size );
-
-/**
- * Check if operation is pending on the specified operation key.
- * The \c op_key must have been initialized with #pj_ioqueue_op_key_init()
- * or submitted as pending operation before, or otherwise the result
- * is undefined.
- *
- * @param key The key.
- * @param op_key The operation key, previously submitted to any of
- * the I/O functions and has returned PJ_EPENDING.
- *
- * @return Non-zero if operation is still pending.
- */
-PJ_DECL(pj_bool_t) pj_ioqueue_is_pending( pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key );
-
-
-/**
- * Post completion status to the specified operation key and call the
- * appropriate callback. When the callback is called, the number of bytes
- * received in read/write callback or the status in accept/connect callback
- * will be set from the \c bytes_status parameter.
- *
- * @param key The key.
- * @param op_key Pending operation key.
- * @param bytes_status Number of bytes or status to be set. A good value
- * to put here is -PJ_ECANCELLED.
- *
- * @return PJ_SUCCESS if completion status has been successfully
- * sent.
- */
-PJ_DECL(pj_status_t) pj_ioqueue_post_completion( pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- pj_ssize_t bytes_status );
-
-
-
-#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
-/**
- * Instruct I/O Queue to accept incoming connection on the specified
- * listening socket. This function will return immediately (i.e. non-blocking)
- * regardless whether a connection is immediately available. If the function
- * can't complete immediately, the caller will be notified about the incoming
- * connection when it calls pj_ioqueue_poll(). If a new connection is
- * immediately available, the function returns PJ_SUCCESS with the new
- * connection; in this case, the callback WILL NOT be called.
- *
- * @param key The key which registered to the server socket.
- * @param op_key An operation specific key to be associated with the
- * pending operation, so that application can keep track of
- * which operation has been completed when the callback is
- * called.
- * @param new_sock Argument which contain pointer to receive the new socket
- * for the incoming connection.
- * @param local Optional argument which contain pointer to variable to
- * receive local address.
- * @param remote Optional argument which contain pointer to variable to
- * receive the remote address.
- * @param addrlen On input, contains the length of the buffer for the
- * address, and on output, contains the actual length of the
- * address. This argument is optional.
- * @return
- * - PJ_SUCCESS When connection is available immediately, and the
- * parameters will be updated to contain information about
- * the new connection. In this case, a completion callback
- * WILL NOT be called.
- * - PJ_EPENDING If no connection is available immediately. When a new
- * connection arrives, the callback will be called.
- * - non-zero which indicates the appropriate error code.
- */
-PJ_DECL(pj_status_t) pj_ioqueue_accept( pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- pj_sock_t *sock,
- pj_sockaddr_t *local,
- pj_sockaddr_t *remote,
- int *addrlen );
-
-/**
- * Initiate non-blocking socket connect. If the socket can NOT be connected
- * immediately, asynchronous connect() will be scheduled and caller will be
- * notified via completion callback when it calls pj_ioqueue_poll(). If
- * socket is connected immediately, the function returns PJ_SUCCESS and
- * completion callback WILL NOT be called.
- *
- * @param key The key associated with TCP socket
- * @param addr The remote address.
- * @param addrlen The remote address length.
- *
- * @return
- * - PJ_SUCCESS If socket is connected immediately. In this case, the
- * completion callback WILL NOT be called.
- * - PJ_EPENDING If operation is queued, or
- * - non-zero Indicates the error code.
- */
-PJ_DECL(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key,
- const pj_sockaddr_t *addr,
- int addrlen );
-
-#endif /* PJ_HAS_TCP */
-
-/**
- * Poll the I/O Queue for completed events.
- *
- * @param ioque the I/O Queue.
- * @param timeout polling timeout, or NULL if the thread wishes to wait
- * indefinetely for the event.
- *
- * @return
- * - zero if timed out (no event).
- * - (<0) if error occured during polling. Callback will NOT be called.
- * - (>1) to indicate numbers of events. Callbacks have been called.
- */
-PJ_DECL(int) pj_ioqueue_poll( pj_ioqueue_t *ioque,
- const pj_time_val *timeout);
-
-
-/**
- * Instruct the I/O Queue to read from the specified handle. This function
- * returns immediately (i.e. non-blocking) regardless whether some data has
- * been transfered. If the operation can't complete immediately, caller will
- * be notified about the completion when it calls pj_ioqueue_poll(). If data
- * is immediately available, the function will return PJ_SUCCESS and the
- * callback WILL NOT be called.
- *
- * @param key The key that uniquely identifies the handle.
- * @param op_key An operation specific key to be associated with the
- * pending operation, so that application can keep track of
- * which operation has been completed when the callback is
- * called. Caller must make sure that this key remains
- * valid until the function completes.
- * @param buffer The buffer to hold the read data. The caller MUST make sure
- * that this buffer remain valid until the framework completes
- * reading the handle.
- * @param length On input, it specifies the size of the buffer. If data is
- * available to be read immediately, the function returns
- * PJ_SUCCESS and this argument will be filled with the
- * amount of data read. If the function is pending, caller
- * will be notified about the amount of data read in the
- * callback. This parameter can point to local variable in
- * caller's stack and doesn't have to remain valid for the
- * duration of pending operation.
- * @param flags Recv flag. If flags has PJ_IOQUEUE_ALWAYS_ASYNC then
- * the function will never return PJ_SUCCESS.
- *
- * @return
- * - PJ_SUCCESS If immediate data has been received in the buffer. In this
- * case, the callback WILL NOT be called.
- * - PJ_EPENDING If the operation has been queued, and the callback will be
- * called when data has been received.
- * - non-zero The return value indicates the error code.
- */
-PJ_DECL(pj_status_t) pj_ioqueue_recv( pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- void *buffer,
- pj_ssize_t *length,
- pj_uint32_t flags );
-
-/**
- * This function behaves similarly as #pj_ioqueue_recv(), except that it is
- * normally called for socket, and the remote address will also be returned
- * along with the data. Caller MUST make sure that both buffer and addr
- * remain valid until the framework completes reading the data.
- *
- * @param key The key that uniquely identifies the handle.
- * @param op_key An operation specific key to be associated with the
- * pending operation, so that application can keep track of
- * which operation has been completed when the callback is
- * called.
- * @param buffer The buffer to hold the read data. The caller MUST make sure
- * that this buffer remain valid until the framework completes
- * reading the handle.
- * @param length On input, it specifies the size of the buffer. If data is
- * available to be read immediately, the function returns
- * PJ_SUCCESS and this argument will be filled with the
- * amount of data read. If the function is pending, caller
- * will be notified about the amount of data read in the
- * callback. This parameter can point to local variable in
- * caller's stack and doesn't have to remain valid for the
- * duration of pending operation.
- * @param flags Recv flag. If flags has PJ_IOQUEUE_ALWAYS_ASYNC then
- * the function will never return PJ_SUCCESS.
- * @param addr Optional Pointer to buffer to receive the address.
- * @param addrlen On input, specifies the length of the address buffer.
- * On output, it will be filled with the actual length of
- * the address. This argument can be NULL if \c addr is not
- * specified.
- *
- * @return
- * - PJ_SUCCESS If immediate data has been received. In this case, the
- * callback must have been called before this function
- * returns, and no pending operation is scheduled.
- * - PJ_EPENDING If the operation has been queued.
- * - non-zero The return value indicates the error code.
- */
-PJ_DECL(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- void *buffer,
- pj_ssize_t *length,
- pj_uint32_t flags,
- pj_sockaddr_t *addr,
- int *addrlen);
-
-/**
- * Instruct the I/O Queue to write to the handle. This function will return
- * immediately (i.e. non-blocking) regardless whether some data has been
- * transfered. If the function can't complete immediately, the caller will
- * be notified about the completion when it calls pj_ioqueue_poll(). If
- * operation completes immediately and data has been transfered, the function
- * returns PJ_SUCCESS and the callback will NOT be called.
- *
- * @param key The key that identifies the handle.
- * @param op_key An operation specific key to be associated with the
- * pending operation, so that application can keep track of
- * which operation has been completed when the callback is
- * called.
- * @param data The data to send. Caller MUST make sure that this buffer
- * remains valid until the write operation completes.
- * @param length On input, it specifies the length of data to send. When
- * data was sent immediately, this function returns PJ_SUCCESS
- * and this parameter contains the length of data sent. If
- * data can not be sent immediately, an asynchronous operation
- * is scheduled and caller will be notified via callback the
- * number of bytes sent. This parameter can point to local
- * variable on caller's stack and doesn't have to remain
- * valid until the operation has completed.
- * @param flags Send flags. If flags has PJ_IOQUEUE_ALWAYS_ASYNC then
- * the function will never return PJ_SUCCESS.
- *
- * @return
- * - PJ_SUCCESS If data was immediately transfered. In this case, no
- * pending operation has been scheduled and the callback
- * WILL NOT be called.
- * - PJ_EPENDING If the operation has been queued. Once data base been
- * transfered, the callback will be called.
- * - non-zero The return value indicates the error code.
- */
-PJ_DECL(pj_status_t) pj_ioqueue_send( pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- const void *data,
- pj_ssize_t *length,
- pj_uint32_t flags );
-
-
-/**
- * Instruct the I/O Queue to write to the handle. This function will return
- * immediately (i.e. non-blocking) regardless whether some data has been
- * transfered. If the function can't complete immediately, the caller will
- * be notified about the completion when it calls pj_ioqueue_poll(). If
- * operation completes immediately and data has been transfered, the function
- * returns PJ_SUCCESS and the callback will NOT be called.
- *
- * @param key the key that identifies the handle.
- * @param op_key An operation specific key to be associated with the
- * pending operation, so that application can keep track of
- * which operation has been completed when the callback is
- * called.
- * @param data the data to send. Caller MUST make sure that this buffer
- * remains valid until the write operation completes.
- * @param length On input, it specifies the length of data to send. When
- * data was sent immediately, this function returns PJ_SUCCESS
- * and this parameter contains the length of data sent. If
- * data can not be sent immediately, an asynchronous operation
- * is scheduled and caller will be notified via callback the
- * number of bytes sent. This parameter can point to local
- * variable on caller's stack and doesn't have to remain
- * valid until the operation has completed.
- * @param flags send flags. If flags has PJ_IOQUEUE_ALWAYS_ASYNC then
- * the function will never return PJ_SUCCESS.
- * @param addr Optional remote address.
- * @param addrlen Remote address length, \c addr is specified.
- *
- * @return
- * - PJ_SUCCESS If data was immediately written.
- * - PJ_EPENDING If the operation has been queued.
- * - non-zero The return value indicates the error code.
- */
-PJ_DECL(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- const void *data,
- pj_ssize_t *length,
- pj_uint32_t flags,
- const pj_sockaddr_t *addr,
- int addrlen);
-
-
-/**
- * !}
- */
-
-PJ_END_DECL
-
-#endif /* __PJ_IOQUEUE_H__ */
-
+/* $Id$ + */ +/* + * Copyright (C)2003-2006 Benny Prijono <benny@prijono.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __PJ_IOQUEUE_H__ +#define __PJ_IOQUEUE_H__ + +/** + * @file ioqueue.h + * @brief I/O Dispatching Mechanism + */ + +#include <pj/types.h> + +PJ_BEGIN_DECL + +/** + * @defgroup PJ_IO Input/Output + * @brief Input/Output + * @ingroup PJ_OS + * + * This section contains API building blocks to perform network I/O and + * communications. If provides: + * - @ref PJ_SOCK + *\n + * A highly portable socket abstraction, runs on all kind of + * network APIs such as standard BSD socket, Windows socket, Linux + * \b kernel socket, PalmOS networking API, etc. + * + * - @ref pj_addr_resolve + *\n + * Portable address resolution, which implements #pj_gethostbyname(). + * + * - @ref PJ_SOCK_SELECT + *\n + * A portable \a select() like API (#pj_sock_select()) which can be + * implemented with various back-ends. + * + * - @ref PJ_IOQUEUE + *\n + * Framework for dispatching network events. + * + * For more information see the modules below. + */ + +/** + * @defgroup PJ_IOQUEUE I/O Event Dispatching Queue + * @ingroup PJ_IO + * @{ + * + * I/O Queue provides API for performing asynchronous I/O operations. It + * conforms to proactor pattern, which allows application to submit an + * asynchronous operation and to be notified later when the operation has + * completed. + * + * The I/O Queue can work on both socket and file descriptors. For + * asynchronous file operations however, one must make sure that the correct + * file I/O back-end is used, because not all file I/O back-end can be + * used with the ioqueue. Please see \ref PJ_FILE_IO for more details. + * + * The framework works natively in platforms where asynchronous operation API + * exists, such as in Windows NT with IoCompletionPort/IOCP. In other + * platforms, the I/O queue abstracts the operating system's event poll API + * to provide semantics similar to IoCompletionPort with minimal penalties + * (i.e. per ioqueue and per handle mutex protection). + * + * The I/O queue provides more than just unified abstraction. It also: + * - makes sure that the operation uses the most effective way to utilize + * the underlying mechanism, to achieve the maximum theoritical + * throughput possible on a given platform. + * - choose the most efficient mechanism for event polling on a given + * platform. + * + * Currently, the I/O Queue is implemented using: + * - <tt><b>select()</b></tt>, as the common denominator, but the least + * efficient. Also the number of descriptor is limited to + * \c PJ_IOQUEUE_MAX_HANDLES (which by default is 64). + * - <tt><b>/dev/epoll</b></tt> on Linux (user mode and kernel mode), + * a much faster replacement for select() on Linux (and more importantly + * doesn't have limitation on number of descriptors). + * - <b>I/O Completion ports</b> on Windows NT/2000/XP, which is the most + * efficient way to dispatch events in Windows NT based OSes, and most + * importantly, it doesn't have the limit on how many handles to monitor. + * And it works with files (not only sockets) as well. + * + * + * \section pj_ioqueue_concurrency_sec Concurrency Rules + * + * The items below describe rules that must be obeyed when using the I/O + * queue, with regard to concurrency: + * - simultaneous operations (by different threads) to different key is safe. + * - simultaneous operations to the same key is also safe, except + * <b>unregistration</b>, which is described below. + * - <b>care must be taken when unregistering a key</b> from the + * ioqueue. Application must take care that when one thread is issuing + * an unregistration, other thread is not simultaneously invoking an + * operation <b>to the same key</b>. + *\n + * This happens because the ioqueue functions are working with a pointer + * to the key, and there is a possible race condition where the pointer + * has been rendered invalid by other threads before the ioqueue has a + * chance to acquire mutex on it. + * + * \section pj_ioqeuue_examples_sec Examples + * + * For some examples on how to use the I/O Queue, please see: + * + * - \ref page_pjlib_ioqueue_tcp_test + * - \ref page_pjlib_ioqueue_udp_test + * - \ref page_pjlib_ioqueue_perf_test + */ + + +/** + * This structure describes operation specific key to be submitted to + * I/O Queue when performing the asynchronous operation. This key will + * be returned to the application when completion callback is called. + * + * Application normally wants to attach it's specific data in the + * \c user_data field so that it can keep track of which operation has + * completed when the callback is called. Alternatively, application can + * also extend this struct to include its data, because the pointer that + * is returned in the completion callback will be exactly the same as + * the pointer supplied when the asynchronous function is called. + */ +typedef struct pj_ioqueue_op_key_t +{ + void *internal__[32]; /**< Internal I/O Queue data. */ + void *user_data; /**< Application data. */ +} pj_ioqueue_op_key_t; + +/** + * This structure describes the callbacks to be called when I/O operation + * completes. + */ +typedef struct pj_ioqueue_callback +{ + /** + * This callback is called when #pj_ioqueue_recv or #pj_ioqueue_recvfrom + * completes. + * + * @param key The key. + * @param op_key Operation key. + * @param bytes_read >= 0 to indicate the amount of data read, + * otherwise negative value containing the error + * code. To obtain the pj_status_t error code, use + * (pj_status_t code = -bytes_read). + */ + void (*on_read_complete)(pj_ioqueue_key_t *key, + pj_ioqueue_op_key_t *op_key, + pj_ssize_t bytes_read); + + /** + * This callback is called when #pj_ioqueue_write or #pj_ioqueue_sendto + * completes. + * + * @param key The key. + * @param op_key Operation key. + * @param bytes_sent >= 0 to indicate the amount of data written, + * otherwise negative value containing the error + * code. To obtain the pj_status_t error code, use + * (pj_status_t code = -bytes_sent). + */ + void (*on_write_complete)(pj_ioqueue_key_t *key, + pj_ioqueue_op_key_t *op_key, + pj_ssize_t bytes_sent); + + /** + * This callback is called when #pj_ioqueue_accept completes. + * + * @param key The key. + * @param op_key Operation key. + * @param sock Newly connected socket. + * @param status Zero if the operation completes successfully. + */ + void (*on_accept_complete)(pj_ioqueue_key_t *key, + pj_ioqueue_op_key_t *op_key, + pj_sock_t sock, + pj_status_t status); + + /** + * This callback is called when #pj_ioqueue_connect completes. + * + * @param key The key. + * @param status PJ_SUCCESS if the operation completes successfully. + */ + void (*on_connect_complete)(pj_ioqueue_key_t *key, + pj_status_t status); +} pj_ioqueue_callback; + + +/** + * Types of pending I/O Queue operation. This enumeration is only used + * internally within the ioqueue. + */ +typedef enum pj_ioqueue_operation_e +{ + PJ_IOQUEUE_OP_NONE = 0, /**< No operation. */ + PJ_IOQUEUE_OP_READ = 1, /**< read() operation. */ + PJ_IOQUEUE_OP_RECV = 2, /**< recv() operation. */ + PJ_IOQUEUE_OP_RECV_FROM = 4, /**< recvfrom() operation. */ + PJ_IOQUEUE_OP_WRITE = 8, /**< write() operation. */ + PJ_IOQUEUE_OP_SEND = 16, /**< send() operation. */ + PJ_IOQUEUE_OP_SEND_TO = 32, /**< sendto() operation. */ +#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0 + PJ_IOQUEUE_OP_ACCEPT = 64, /**< accept() operation. */ + PJ_IOQUEUE_OP_CONNECT = 128, /**< connect() operation. */ +#endif /* PJ_HAS_TCP */ +} pj_ioqueue_operation_e; + + +/** + * This macro specifies the maximum number of events that can be + * processed by the ioqueue on a single poll cycle, on implementation + * that supports it. The value is only meaningfull when specified + * during PJLIB build. + */ +#ifndef PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL +# define PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL (16) +#endif + +/** + * When this flag is specified in ioqueue's recv() or send() operations, + * the ioqueue will always mark the operation as asynchronous. + */ +#define PJ_IOQUEUE_ALWAYS_ASYNC ((pj_uint32_t)1 << (pj_uint32_t)31) + +/** + * Return the name of the ioqueue implementation. + * + * @return Implementation name. + */ +PJ_DECL(const char*) pj_ioqueue_name(void); + + +/** + * Create a new I/O Queue framework. + * + * @param pool The pool to allocate the I/O queue structure. + * @param max_fd The maximum number of handles to be supported, which + * should not exceed PJ_IOQUEUE_MAX_HANDLES. + * @param ioqueue Pointer to hold the newly created I/O Queue. + * + * @return PJ_SUCCESS on success. + */ +PJ_DECL(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, + pj_size_t max_fd, + pj_ioqueue_t **ioqueue); + +/** + * Destroy the I/O queue. + * + * @param ioque The I/O Queue to be destroyed. + * + * @return PJ_SUCCESS if success. + */ +PJ_DECL(pj_status_t) pj_ioqueue_destroy( pj_ioqueue_t *ioque ); + +/** + * Set the lock object to be used by the I/O Queue. This function can only + * be called right after the I/O queue is created, before any handle is + * registered to the I/O queue. + * + * Initially the I/O queue is created with non-recursive mutex protection. + * Applications can supply alternative lock to be used by calling this + * function. + * + * @param ioque The ioqueue instance. + * @param lock The lock to be used by the ioqueue. + * @param auto_delete In non-zero, the lock will be deleted by the ioqueue. + * + * @return PJ_SUCCESS or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioque, + pj_lock_t *lock, + pj_bool_t auto_delete ); + +/** + * Register a socket to the I/O queue framework. + * When a socket is registered to the IOQueue, it may be modified to use + * non-blocking IO. If it is modified, there is no guarantee that this + * modification will be restored after the socket is unregistered. + * + * @param pool To allocate the resource for the specified handle, + * which must be valid until the handle/key is unregistered + * from I/O Queue. + * @param ioque The I/O Queue. + * @param sock The socket. + * @param user_data User data to be associated with the key, which can be + * retrieved later. + * @param cb Callback to be called when I/O operation completes. + * @param key Pointer to receive the key to be associated with this + * socket. Subsequent I/O queue operation will need this + * key. + * + * @return PJ_SUCCESS on success, or the error code. + */ +PJ_DECL(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool, + pj_ioqueue_t *ioque, + pj_sock_t sock, + void *user_data, + const pj_ioqueue_callback *cb, + pj_ioqueue_key_t **key ); + +/** + * Unregister from the I/O Queue framework. Caller must make sure that + * the key doesn't have any pending operations before calling this function, + * by calling #pj_ioqueue_is_pending() for all previously submitted + * operations except asynchronous connect, and if necessary call + * #pj_ioqueue_post_completion() to cancel the pending operations. + * + * Note that asynchronous connect operation will automatically be + * cancelled during the unregistration. + * + * @param key The key that was previously obtained from registration. + * + * @return PJ_SUCCESS on success or the error code. + * + * @see pj_ioqueue_is_pending + */ +PJ_DECL(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key ); + + +/** + * Get user data associated with an ioqueue key. + * + * @param key The key that was previously obtained from registration. + * + * @return The user data associated with the descriptor, or NULL + * on error or if no data is associated with the key during + * registration. + */ +PJ_DECL(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key ); + +/** + * Set or change the user data to be associated with the file descriptor or + * handle or socket descriptor. + * + * @param key The key that was previously obtained from registration. + * @param user_data User data to be associated with the descriptor. + * @param old_data Optional parameter to retrieve the old user data. + * + * @return PJ_SUCCESS on success or the error code. + */ +PJ_DECL(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key, + void *user_data, + void **old_data); + + +/** + * Initialize operation key. + * + * @param op_key The operation key to be initialied. + * @param size The size of the operation key. + */ +PJ_DECL(void) pj_ioqueue_op_key_init( pj_ioqueue_op_key_t *op_key, + pj_size_t size ); + +/** + * Check if operation is pending on the specified operation key. + * The \c op_key must have been initialized with #pj_ioqueue_op_key_init() + * or submitted as pending operation before, or otherwise the result + * is undefined. + * + * @param key The key. + * @param op_key The operation key, previously submitted to any of + * the I/O functions and has returned PJ_EPENDING. + * + * @return Non-zero if operation is still pending. + */ +PJ_DECL(pj_bool_t) pj_ioqueue_is_pending( pj_ioqueue_key_t *key, + pj_ioqueue_op_key_t *op_key ); + + +/** + * Post completion status to the specified operation key and call the + * appropriate callback. When the callback is called, the number of bytes + * received in read/write callback or the status in accept/connect callback + * will be set from the \c bytes_status parameter. + * + * @param key The key. + * @param op_key Pending operation key. + * @param bytes_status Number of bytes or status to be set. A good value + * to put here is -PJ_ECANCELLED. + * + * @return PJ_SUCCESS if completion status has been successfully + * sent. + */ +PJ_DECL(pj_status_t) pj_ioqueue_post_completion( pj_ioqueue_key_t *key, + pj_ioqueue_op_key_t *op_key, + pj_ssize_t bytes_status ); + + + +#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0 +/** + * Instruct I/O Queue to accept incoming connection on the specified + * listening socket. This function will return immediately (i.e. non-blocking) + * regardless whether a connection is immediately available. If the function + * can't complete immediately, the caller will be notified about the incoming + * connection when it calls pj_ioqueue_poll(). If a new connection is + * immediately available, the function returns PJ_SUCCESS with the new + * connection; in this case, the callback WILL NOT be called. + * + * @param key The key which registered to the server socket. + * @param op_key An operation specific key to be associated with the + * pending operation, so that application can keep track of + * which operation has been completed when the callback is + * called. + * @param new_sock Argument which contain pointer to receive the new socket + * for the incoming connection. + * @param local Optional argument which contain pointer to variable to + * receive local address. + * @param remote Optional argument which contain pointer to variable to + * receive the remote address. + * @param addrlen On input, contains the length of the buffer for the + * address, and on output, contains the actual length of the + * address. This argument is optional. + * @return + * - PJ_SUCCESS When connection is available immediately, and the + * parameters will be updated to contain information about + * the new connection. In this case, a completion callback + * WILL NOT be called. + * - PJ_EPENDING If no connection is available immediately. When a new + * connection arrives, the callback will be called. + * - non-zero which indicates the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_ioqueue_accept( pj_ioqueue_key_t *key, + pj_ioqueue_op_key_t *op_key, + pj_sock_t *sock, + pj_sockaddr_t *local, + pj_sockaddr_t *remote, + int *addrlen ); + +/** + * Initiate non-blocking socket connect. If the socket can NOT be connected + * immediately, asynchronous connect() will be scheduled and caller will be + * notified via completion callback when it calls pj_ioqueue_poll(). If + * socket is connected immediately, the function returns PJ_SUCCESS and + * completion callback WILL NOT be called. + * + * @param key The key associated with TCP socket + * @param addr The remote address. + * @param addrlen The remote address length. + * + * @return + * - PJ_SUCCESS If socket is connected immediately. In this case, the + * completion callback WILL NOT be called. + * - PJ_EPENDING If operation is queued, or + * - non-zero Indicates the error code. + */ +PJ_DECL(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key, + const pj_sockaddr_t *addr, + int addrlen ); + +#endif /* PJ_HAS_TCP */ + +/** + * Poll the I/O Queue for completed events. + * + * @param ioque the I/O Queue. + * @param timeout polling timeout, or NULL if the thread wishes to wait + * indefinetely for the event. + * + * @return + * - zero if timed out (no event). + * - (<0) if error occured during polling. Callback will NOT be called. + * - (>1) to indicate numbers of events. Callbacks have been called. + */ +PJ_DECL(int) pj_ioqueue_poll( pj_ioqueue_t *ioque, + const pj_time_val *timeout); + + +/** + * Instruct the I/O Queue to read from the specified handle. This function + * returns immediately (i.e. non-blocking) regardless whether some data has + * been transfered. If the operation can't complete immediately, caller will + * be notified about the completion when it calls pj_ioqueue_poll(). If data + * is immediately available, the function will return PJ_SUCCESS and the + * callback WILL NOT be called. + * + * @param key The key that uniquely identifies the handle. + * @param op_key An operation specific key to be associated with the + * pending operation, so that application can keep track of + * which operation has been completed when the callback is + * called. Caller must make sure that this key remains + * valid until the function completes. + * @param buffer The buffer to hold the read data. The caller MUST make sure + * that this buffer remain valid until the framework completes + * reading the handle. + * @param length On input, it specifies the size of the buffer. If data is + * available to be read immediately, the function returns + * PJ_SUCCESS and this argument will be filled with the + * amount of data read. If the function is pending, caller + * will be notified about the amount of data read in the + * callback. This parameter can point to local variable in + * caller's stack and doesn't have to remain valid for the + * duration of pending operation. + * @param flags Recv flag. If flags has PJ_IOQUEUE_ALWAYS_ASYNC then + * the function will never return PJ_SUCCESS. + * + * @return + * - PJ_SUCCESS If immediate data has been received in the buffer. In this + * case, the callback WILL NOT be called. + * - PJ_EPENDING If the operation has been queued, and the callback will be + * called when data has been received. + * - non-zero The return value indicates the error code. + */ +PJ_DECL(pj_status_t) pj_ioqueue_recv( pj_ioqueue_key_t *key, + pj_ioqueue_op_key_t *op_key, + void *buffer, + pj_ssize_t *length, + pj_uint32_t flags ); + +/** + * This function behaves similarly as #pj_ioqueue_recv(), except that it is + * normally called for socket, and the remote address will also be returned + * along with the data. Caller MUST make sure that both buffer and addr + * remain valid until the framework completes reading the data. + * + * @param key The key that uniquely identifies the handle. + * @param op_key An operation specific key to be associated with the + * pending operation, so that application can keep track of + * which operation has been completed when the callback is + * called. + * @param buffer The buffer to hold the read data. The caller MUST make sure + * that this buffer remain valid until the framework completes + * reading the handle. + * @param length On input, it specifies the size of the buffer. If data is + * available to be read immediately, the function returns + * PJ_SUCCESS and this argument will be filled with the + * amount of data read. If the function is pending, caller + * will be notified about the amount of data read in the + * callback. This parameter can point to local variable in + * caller's stack and doesn't have to remain valid for the + * duration of pending operation. + * @param flags Recv flag. If flags has PJ_IOQUEUE_ALWAYS_ASYNC then + * the function will never return PJ_SUCCESS. + * @param addr Optional Pointer to buffer to receive the address. + * @param addrlen On input, specifies the length of the address buffer. + * On output, it will be filled with the actual length of + * the address. This argument can be NULL if \c addr is not + * specified. + * + * @return + * - PJ_SUCCESS If immediate data has been received. In this case, the + * callback must have been called before this function + * returns, and no pending operation is scheduled. + * - PJ_EPENDING If the operation has been queued. + * - non-zero The return value indicates the error code. + */ +PJ_DECL(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key, + pj_ioqueue_op_key_t *op_key, + void *buffer, + pj_ssize_t *length, + pj_uint32_t flags, + pj_sockaddr_t *addr, + int *addrlen); + +/** + * Instruct the I/O Queue to write to the handle. This function will return + * immediately (i.e. non-blocking) regardless whether some data has been + * transfered. If the function can't complete immediately, the caller will + * be notified about the completion when it calls pj_ioqueue_poll(). If + * operation completes immediately and data has been transfered, the function + * returns PJ_SUCCESS and the callback will NOT be called. + * + * @param key The key that identifies the handle. + * @param op_key An operation specific key to be associated with the + * pending operation, so that application can keep track of + * which operation has been completed when the callback is + * called. + * @param data The data to send. Caller MUST make sure that this buffer + * remains valid until the write operation completes. + * @param length On input, it specifies the length of data to send. When + * data was sent immediately, this function returns PJ_SUCCESS + * and this parameter contains the length of data sent. If + * data can not be sent immediately, an asynchronous operation + * is scheduled and caller will be notified via callback the + * number of bytes sent. This parameter can point to local + * variable on caller's stack and doesn't have to remain + * valid until the operation has completed. + * @param flags Send flags. If flags has PJ_IOQUEUE_ALWAYS_ASYNC then + * the function will never return PJ_SUCCESS. + * + * @return + * - PJ_SUCCESS If data was immediately transfered. In this case, no + * pending operation has been scheduled and the callback + * WILL NOT be called. + * - PJ_EPENDING If the operation has been queued. Once data base been + * transfered, the callback will be called. + * - non-zero The return value indicates the error code. + */ +PJ_DECL(pj_status_t) pj_ioqueue_send( pj_ioqueue_key_t *key, + pj_ioqueue_op_key_t *op_key, + const void *data, + pj_ssize_t *length, + pj_uint32_t flags ); + + +/** + * Instruct the I/O Queue to write to the handle. This function will return + * immediately (i.e. non-blocking) regardless whether some data has been + * transfered. If the function can't complete immediately, the caller will + * be notified about the completion when it calls pj_ioqueue_poll(). If + * operation completes immediately and data has been transfered, the function + * returns PJ_SUCCESS and the callback will NOT be called. + * + * @param key the key that identifies the handle. + * @param op_key An operation specific key to be associated with the + * pending operation, so that application can keep track of + * which operation has been completed when the callback is + * called. + * @param data the data to send. Caller MUST make sure that this buffer + * remains valid until the write operation completes. + * @param length On input, it specifies the length of data to send. When + * data was sent immediately, this function returns PJ_SUCCESS + * and this parameter contains the length of data sent. If + * data can not be sent immediately, an asynchronous operation + * is scheduled and caller will be notified via callback the + * number of bytes sent. This parameter can point to local + * variable on caller's stack and doesn't have to remain + * valid until the operation has completed. + * @param flags send flags. If flags has PJ_IOQUEUE_ALWAYS_ASYNC then + * the function will never return PJ_SUCCESS. + * @param addr Optional remote address. + * @param addrlen Remote address length, \c addr is specified. + * + * @return + * - PJ_SUCCESS If data was immediately written. + * - PJ_EPENDING If the operation has been queued. + * - non-zero The return value indicates the error code. + */ +PJ_DECL(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key, + pj_ioqueue_op_key_t *op_key, + const void *data, + pj_ssize_t *length, + pj_uint32_t flags, + const pj_sockaddr_t *addr, + int addrlen); + + +/** + * !} + */ + +PJ_END_DECL + +#endif /* __PJ_IOQUEUE_H__ */ + |