/* * * (c) Copyright 1989 OPEN SOFTWARE FOUNDATION, INC. * (c) Copyright 1989 HEWLETT-PACKARD COMPANY * (c) Copyright 1989 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. * */ /* */ /* ** ** 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_. * 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 _DCE_PROTOTYPE_(( 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 _DCE_PROTOTYPE_(( rpc_protseq_id_t /*pseq_id*/, rpc_dg_sock_pool_elt_p_t * /*sp_elt*/ )); PRIVATE void rpc__dg_network_disable_desc _DCE_PROTOTYPE_(( rpc_dg_sock_pool_elt_p_t /*sp_elt*/ )); PRIVATE void rpc__dg_network_init _DCE_PROTOTYPE_((void)); PRIVATE void rpc__dg_network_fork_handler _DCE_PROTOTYPE_(( rpc_fork_stage_id_t /*stage*/ )); PRIVATE void rpc__dg_network_sock_release _DCE_PROTOTYPE_(( rpc_dg_sock_pool_elt_p_t * /*sp*/ )); PRIVATE void rpc__dg_network_sock_reference _DCE_PROTOTYPE_(( rpc_dg_sock_pool_elt_p_t /*sp*/ )); #endif /* _DGSOC_H */