dgsoc.h   [plain text]


/*
 * Copyright (c) 2010 Apple Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Portions of this software have been released under the following terms:
 *
 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC.
 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY
 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION
 *
 * To anyone who acknowledges that this file is provided "AS IS"
 * without any express or implied warranty:
 * permission to use, copy, modify, and distribute this file for any
 * purpose is hereby granted without fee, provided that the above
 * copyright notices and this notice appears in all source code copies,
 * and that none of the names of Open Software Foundation, Inc., Hewlett-
 * Packard Company or Digital Equipment Corporation be used
 * in advertising or publicity pertaining to distribution of the software
 * without specific, written prior permission.  Neither Open Software
 * Foundation, Inc., Hewlett-Packard Company nor Digital
 * Equipment Corporation makes any representations about the suitability
 * of this software for any purpose.
 *
 * Copyright (c) 2007, Novell, Inc. All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 3.  Neither the name of Novell Inc. nor the names of its contributors
 *     may be used to endorse or promote products derived from this
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @APPLE_LICENSE_HEADER_END@
 */

/*
**
**  NAME:
**
**      dgsoc.h
**
**  FACILITY:
**
**      Remote Procedure Call (RPC)
**
**  ABSTRACT:
**
**  Routines for managing the socket pool.
**
**
*/

#ifndef _DGSOC_H
#define _DGSOC_H

/*
 * The Socket Pool
 *
 * Sockets are allocated by a call to rpc__dg_network_use_protseq_<cl,sv>.
 * For servers, a new socket is opened on each call.  Clients will reuse
 * an already open socket if it is of the correct protocol sequence,
 * and it was opened as a client socket.  Either way, we start by
 * finding/creating a suitable new/used entry in the socket pool.
 *
 * Pool elements are reference counted.  When the only remaining reference
 * count is the pool's internal table, the pool element is freed (including
 * closing its associated socket descriptor). Thus, socket users holding
 * a reference are not forced to lock the socket pool before using a
 * descriptor to prevent the descriptor from disappearing.
 *
 * In the event of multiple consecutive errors, a socket can be set to
 * disabled.  Disabling removes the socket from the pool of descriptors
 * being listened on by the listener thread.  For socket users, the
 * disabled flag is advisory.  Since the socket user has a refcnt, it
 * needn't worry that the socket could be closed between the check of
 * the disabled flag and the actual use of the socket.
 *
 * Before performing a socket operation, threads should always check
 * that the socket they are using has not been marked disabled.  This
 * condition is advisory, but it does indicate that subsequent use of the
 * socket is pointless; use RPC_DG_NETWORK_IS_DISABLED_DESC().
 *
 * Locking considerations:
 *
 * All fields within the socket pool and its entries are protected by
 * the the socket pool lock except:
 *
 *     The error_cnt field can be updated by any thread with a reference
 *     to the pool entry.  We accept the possibility that an update may
 *     get lost.  However, it is presumed that while a socket is
 *     functioning correctly, all writers to this field will be writing
 *     0, and if the socket fails, all writers will be doing increments
 *     until the maximum number of consecutive errors has been reached.
 *     It is not critical that every increment be successful, whereas
 *     it is critical, for performance reasons, that we don't force socket
 *     users to take a lock to update this field every time they read/write
 *     from a socket.
 *
 *     Note that we force storage unit alignment of the "error_cnt".  This
 *     is done because we must worry about hardware environments in which
 *     the code that references less-than-memory-word units ends up
 *     dragging some larger unit from main memory, modifying some portion
 *     and storing the unit back.  This would end up reading and writing
 *     other pool_elt bits which are protected by the pool mutex (which
 *     we won't be holding).
 *
 *     The disabled flag for a pool entry can be read at anytime by threads
 *     which hold a reference to the entry.  The reference count guarantees
 *     the socket is still open, the disabled flag is merely an effort
 *     to inform users of the socket that they needn't bother trying
 *     to use the socket any further.  However, no harm will result if
 *     they miss the flag and try to use the the socket anyway.
 *
 *     Similarly, the is_private field can be read by any call with a
 *     reference to the entry.  This value never changes.
 *
 *     The xqe and rqe pointers are only used by private sockets.  They
 *     are initialized at the time the socket pool element is created.
 *     After that, they are protected by the call handle lock of the
 *     call that is using (holds the reference to) the private socket.
 */

typedef struct rpc_dg_sock_pool_elt_t {
    struct rpc_dg_sock_pool_elt_t *next;
    rpc_protseq_id_t pseq_id;
    rpc_socket_t sock;
    unsigned32 rcvbuf;
    unsigned32 sndbuf;
    rpc_addr_vector_p_t brd_addrs;
    rpc_dg_recvq_elt_p_t rqe;
    rpc_dg_xmitq_elt_p_t xqe;
    rpc_dg_recvq_elt_p_t rqe_list;  /* cached pkts */
    unsigned32 rqe_list_len;
    rpc_dg_ccall_p_t ccall;         /* only valid if is_private   */
    unsigned32 refcnt;
    unsigned        : 0;            /* force alignment; see above */
    unsigned8 error_cnt;
    unsigned        : 0;            /* force alignment; see above */
    unsigned is_server: 1;
    unsigned is_disabled: 1;
    unsigned is_private: 1;
    unsigned rqe_available: 1;
} rpc_dg_sock_pool_elt_t, *rpc_dg_sock_pool_elt_p_t;

typedef struct rpc_dg_sock_pool_t {
    unsigned32  num_entries;
    rpc_mutex_t sp_mutex;
    rpc_dg_sock_pool_elt_p_t private_sockets;
    rpc_dg_sock_pool_elt_p_t shared_sockets;
} rpc_dg_sock_pool_t;

/*
 * Number of consecutive EIO errors we'll allow before disabling a socket.
 */
#ifndef RPC_C_DG_SOCK_MAX_ERRORS
#define RPC_C_DG_SOCK_MAX_ERRORS 10
#endif

/*
 * Number of private client sockets allowed for each address family.
 * Currently disabled for kernel RPC
 */
#ifndef RPC_C_DG_SOCK_MAX_PRIV_SOCKS
#define RPC_C_DG_SOCK_MAX_PRIV_SOCKS 3
#endif

/*
 * Return whether or not the sock pool elt's descriptor is disabled.
 * Done as a macro just to isolate users in case we want to change
 * the locking requirements (see above).
 */
#define RPC_DG_SOCK_IS_DISABLED(sp_elt)  ((sp_elt)->is_disabled)

/*
 * This macro should be called after each send/receive on a socket.  If
 * the call was successful, the count of consecutive errors is reset.
 * On error, the count is incremented, and if the count exceeds the maximum
 * allowed, the socket is disabled.
 *
 * We only check for EIO errors.  In the future we may want to check
 * for other errors as well.
 */
#define RPC_DG_SOCK_UPDATE_ERR_COUNT(sp_elt, serr) \
{ \
    if ((serr) != RPC_C_SOCKET_EIO) \
        (sp_elt)->error_cnt = 0; \
    else \
    { \
        if (++((sp_elt)->error_cnt) >= RPC_C_DG_SOCK_MAX_ERRORS) \
            rpc__dg_network_disable_desc(sp_elt); \
    } \
}

/*
 * Macros for locking/unlocking the socket pool's mutex.
 */

#define RPC_DG_SOCK_POOL_LOCK(junk)    RPC_MUTEX_LOCK(rpc_g_dg_sock_pool.sp_mutex)
#define RPC_DG_SOCK_POOL_UNLOCK(junk)  RPC_MUTEX_UNLOCK(rpc_g_dg_sock_pool.sp_mutex)
#define RPC_DG_SOCK_POOL_LOCK_ASSERT(junk) \
                          RPC_MUTEX_LOCK_ASSERT(rpc_g_dg_sock_pool.sp_mutex)

/* ======================================================================== */

PRIVATE void rpc__dg_network_use_protseq_sv (
        rpc_protseq_id_t  /*pseq_id*/,
        unsigned32  /*max_calls*/,
        rpc_addr_p_t  /*rpc_addr*/,
        unsigned_char_p_t  /*endpoint*/,
        unsigned32 * /*st*/
    );

PRIVATE void rpc__dg_network_use_protseq_cl (
        rpc_protseq_id_t  /*pseq_id*/,
        rpc_dg_sock_pool_elt_p_t * /*sp_elt*/
    );

PRIVATE void rpc__dg_network_disable_desc (
        rpc_dg_sock_pool_elt_p_t  /*sp_elt*/
    );

PRIVATE void rpc__dg_network_init (void);

PRIVATE void rpc__dg_network_fork_handler (
        rpc_fork_stage_id_t  /*stage*/
    );

PRIVATE void rpc__dg_network_sock_release (
        rpc_dg_sock_pool_elt_p_t * /*sp*/
    );

PRIVATE void rpc__dg_network_sock_reference (
        rpc_dg_sock_pool_elt_p_t  /*sp*/
    );

#endif /* _DGSOC_H */