From 20d35b014521ff27bbdacfe5245c8e081a160bb9 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 28 Jul 2015 16:23:28 +0100 Subject: [PATCH] [pool] Add a generic concept of a pooled connection Signed-off-by: Michael Brown --- src/core/pool.c | 114 ++++++++++++++++++++++++++++++++++++ src/include/ipxe/pool.h | 127 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 241 insertions(+) create mode 100644 src/core/pool.c create mode 100644 src/include/ipxe/pool.h diff --git a/src/core/pool.c b/src/core/pool.c new file mode 100644 index 000000000..0163405f7 --- /dev/null +++ b/src/core/pool.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2015 Michael Brown . + * + * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** + * @file + * + * Pooled connections + * + */ + +#include +#include + +/** + * Recycle this connection after closing + * + * @v intf Data transfer interface + */ +void pool_recycle ( struct interface *intf ) { + + intf_poke ( intf, pool_recycle ); +} + +/** + * Reopen a defunct connection + * + * @v intf Data transfer interface + */ +void pool_reopen ( struct interface *intf ) { + + intf_poke ( intf, pool_reopen ); +} + +/** + * Add connection to pool + * + * @v pool Pooled connection + * @v list List of pooled connections + * @v expiry Expiry time + */ +void pool_add ( struct pooled_connection *pool, struct list_head *list, + unsigned long expiry ) { + + /* Sanity check */ + assert ( list_empty ( &pool->list ) ); + assert ( ! timer_running ( &pool->timer ) ); + + /* Add to list of pooled connections */ + list_add_tail ( &pool->list, list ); + + /* Start expiry timer */ + start_timer_fixed ( &pool->timer, expiry ); +} + +/** + * Remove connection from pool + * + * @v pool Pooled connection + */ +void pool_del ( struct pooled_connection *pool ) { + + /* Remove from list of pooled connections */ + list_del ( &pool->list ); + INIT_LIST_HEAD ( &pool->list ); + + /* Stop expiry timer */ + stop_timer ( &pool->timer ); + + /* Mark as a freshly recycled connection */ + pool->flags = POOL_RECYCLED; +} + +/** + * Close expired pooled connection + * + * @v timer Expiry timer + * @v over Failure indicator + */ +void pool_expired ( struct retry_timer *timer, int over __unused ) { + struct pooled_connection *pool = + container_of ( timer, struct pooled_connection, timer ); + + /* Sanity check */ + assert ( ! list_empty ( &pool->list ) ); + + /* Remove from connection pool */ + list_del ( &pool->list ); + INIT_LIST_HEAD ( &pool->list ); + + /* Close expired connection */ + pool->expired ( pool ); +} diff --git a/src/include/ipxe/pool.h b/src/include/ipxe/pool.h new file mode 100644 index 000000000..27066e9b3 --- /dev/null +++ b/src/include/ipxe/pool.h @@ -0,0 +1,127 @@ +#ifndef _IPXE_POOL_H +#define _IPXE_POOL_H + +/** @file + * + * Pooled connections + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include + +/** A pooled connection */ +struct pooled_connection { + /** List of pooled connections + * + * Note that each connecton in the pool has a running expiry + * timer which holds a reference to the connection. We + * therefore do not require the connection pool list to hold a + * reference for each pooled connection. + */ + struct list_head list; + /** Expiry timer */ + struct retry_timer timer; + /** Close expired pooled connection + * + * @v pool Pooled connection + */ + void ( * expired ) ( struct pooled_connection *pool ); + /** Flags */ + unsigned int flags; +}; + +/** Pooled connection flags */ +enum pooled_connection_flags { + /** Connection should be recycled after closing */ + POOL_RECYCLABLE = 0x0001, + /** Connection has been recycled */ + POOL_RECYCLED = 0x0002, + /** Connection is known to be alive */ + POOL_ALIVE = 0x0004, +}; + +extern void pool_add ( struct pooled_connection *pool, struct list_head *list, + unsigned long expiry ); +extern void pool_del ( struct pooled_connection *pool ); +extern void pool_expired ( struct retry_timer *timer, int over ); + +/** + * Initialise a pooled connection + * + * @v pool Pooled connection + * @v expired Close expired pooled connection method + * @v refcnt Containing object reference counter + */ +static inline __attribute__ (( always_inline )) void +pool_init ( struct pooled_connection *pool, + void ( * expired ) ( struct pooled_connection *pool ), + struct refcnt *refcnt ) { + + INIT_LIST_HEAD ( &pool->list ); + timer_init ( &pool->timer, pool_expired, refcnt ); + pool->expired = expired; +} + +/** + * Mark pooled connection as recyclable + * + * @v pool Pooled connection + */ +static inline __attribute__ (( always_inline )) void +pool_recyclable ( struct pooled_connection *pool ) { + + pool->flags |= POOL_RECYCLABLE; +} + +/** + * Mark pooled connection as alive + * + * @v pool Pooled connection + */ +static inline __attribute__ (( always_inline )) void +pool_alive ( struct pooled_connection *pool ) { + + pool->flags |= POOL_ALIVE; +} + +/** + * Check if pooled connection is recyclable + * + * @v pool Pooled connection + * @ret recyclable Pooled connection is recyclable + */ +static inline __attribute__ (( always_inline )) int +pool_is_recyclable ( struct pooled_connection *pool ) { + + return ( pool->flags & POOL_RECYCLABLE ); +} + +/** + * Check if pooled connection is reopenable + * + * @v pool Pooled connection + * @ret reopenable Pooled connection is reopenable + */ +static inline __attribute__ (( always_inline )) int +pool_is_reopenable ( struct pooled_connection *pool ) { + + /* A connection is reopenable if it has been recycled but is + * not yet known to be alive. + */ + return ( ( pool->flags & POOL_RECYCLED ) & + ( ! ( pool->flags & POOL_ALIVE ) ) ); +} + +extern void pool_recycle ( struct interface *intf ); +#define pool_recycle_TYPE( object_type ) \ + typeof ( void ( object_type ) ) + +extern void pool_reopen ( struct interface *intf ); +#define pool_reopen_TYPE( object_type ) \ + typeof ( void ( object_type ) ) + +#endif /* _IPXE_POOL_H */