Revision: 1881
http://undernet-ircu.svn.sourceforge.net/undernet-ircu/?rev=1881&view=rev
Author: klmitch
Date: 2008-09-26 04:15:18 +0000 (Fri, 26 Sep 2008)
Log Message:
-----------
Author: Kev <[EMAIL PROTECTED]>
Description:
First, fix a minor bug in ancillary.h. Second, define the concept of
"keys" and "keyspaces" utilizing a small, efficient algorithm for
finding an available integer array index where availability is stored
by a dynamically allocated bitmap. Finally, update mode.h to use a
keyspace in struct ModeList (and update its style to match the rest
of ircu).
Modified Paths:
--------------
ircu2/branches/mode/ChangeLog
ircu2/branches/mode/include/ancillary.h
ircu2/branches/mode/include/mode.h
Added Paths:
-----------
ircu2/branches/mode/include/keyspace.h
ircu2/branches/mode/ircd/keyspace.c
Modified: ircu2/branches/mode/ChangeLog
===================================================================
--- ircu2/branches/mode/ChangeLog 2008-09-22 16:46:42 UTC (rev 1880)
+++ ircu2/branches/mode/ChangeLog 2008-09-26 04:15:18 UTC (rev 1881)
@@ -1,3 +1,18 @@
+2008-09-26 Kevin L. Mitchell <[EMAIL PROTECTED]>
+
+ * include/ancillary.h: correct a minor typo in ancdata_init();
+ this eventually needs to be updated to utilize the new keyspace
+ routines
+
+ * include/mode.h: add keyspaces to ModeList; update style from
+ mine to ircu's
+
+ * include/keyspace.h: types, structures, etc. for allocating and
+ deallocating "keys" from "keyspaces"
+
+ * ircd/keyspace.c: generic routines to allocate and deallocate
+ "keys" from a "keyspace"
+
2008-09-22 Kevin L. Mitchell <[EMAIL PROTECTED]>
* include/mode.h: begin sketching out structures for new, unified
Modified: ircu2/branches/mode/include/ancillary.h
===================================================================
--- ircu2/branches/mode/include/ancillary.h 2008-09-22 16:46:42 UTC (rev
1880)
+++ ircu2/branches/mode/include/ancillary.h 2008-09-26 04:15:18 UTC (rev
1881)
@@ -117,12 +117,12 @@
{ (module), 0, 0 }
/** Dynamically initialize an ancdata_t.
- * @param[in,out] ad The ancdata_t to be initialized.
+ * @param[in,out] ad A pointer to the ancdata_t to be initialized.
* @param[in] module The module the object is in.
*/
#define ancdata_init(ad, module) \
do { \
- ancdata_t _ad = (ad); \
+ ancdata_t *_ad = (ad); \
_ad->ad_module = (module); \
_ad->ad_alloc = 0; \
_ad->ad_data = 0; \
Added: ircu2/branches/mode/include/keyspace.h
===================================================================
--- ircu2/branches/mode/include/keyspace.h (rev 0)
+++ ircu2/branches/mode/include/keyspace.h 2008-09-26 04:15:18 UTC (rev
1881)
@@ -0,0 +1,126 @@
+/*
+ * IRC - Internet Relay Chat, include/keyspace.h
+ * Copyright (C) 2008 Kevin L. Mitchell
+ *
+ * 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, 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
+ */
+/** @file
+ * @brief Structures and functions for allocating integer keys.
+ * @version $Id$
+ */
+#ifndef INCLUDED_keyspace_h
+#define INCLUDED_keyspace_h
+#ifndef INCLUDED_flagset_h
+#include "flagset.h" /* flagpage_t */
+#endif
+#ifndef INCLUDED_limits_h
+#include <limits.h> /* UINT_MAX */
+#define INCLUDED_limits_h
+#endif
+
+/** Invalid key_t value for returning errors from ks_reserve(). */
+#define KEY_INVKEY UINT_MAX
+
+/** Specifies a key value. */
+typedef unsigned int key_t;
+/** Specifies a space of keys to allocate from. */
+typedef struct KeySpace keyspace_t;
+
+/** Optional growth callback for a key space.
+ * @param[in] space Key space being grown.
+ * @param[in] new New size for key space allocation.
+ */
+typedef void (*keygrow_t)(keyspace_t* space, key_t new);
+
+/** Contains details of the key space. */
+struct KeySpace {
+ unsigned long ks_magic; /**< Magic number */
+ unsigned int ks_alloc; /**< Total number of bitmap entries */
+ key_t ks_count; /**< Current count of keys */
+ key_t ks_highest; /**< Highest allocated key to date */
+ key_t ks_max; /**< Maximum number of keys to allocate
*/
+ key_t ks_extern; /**< External key tracker size */
+ key_t ks_chunk; /**< Chunk to round key tracker size to
*/
+ keygrow_t ks_grow; /**< External routine to signal on growth */
+ flagpage_t* ks_keys; /**< Key allocation bitmap */
+ void* ks_extra; /**< Extra data associated with
keyspace */
+};
+
+/** Magic number for keyspace_t. */
+#define KEYSPACE_MAGIC 0x44368132
+
+/** Initialize a keyspace_t.
+ * @param[in] max Maximum number of keys that can be reserved.
+ * @param[in] chunk Chunk size for calling external routine.
+ * @param[in] grow External routine to call when grown.
+ * @param[in] extra Extra data to be associated with the keyspace.
+ */
+#define KEYSPACE_INIT(max, chunk, grow, extra) \
+ { KEYSPACE_MAGIC, 0, 0, 0, (max), 0, (chunk), (grow), 0, (extra) }
+
+/** Check the keyspace_t magic number. */
+#define KEYSPACE_CHECK(space) ((space) && \
+ (space)->ks_magic == KEYSPACE_MAGIC)
+
+/** Get the number of entries allocated in the keys table. */
+#define ks_alloc(space) ((space)->ks_alloc)
+/** Get the count of the keys currently allocated. */
+#define ks_count(space) ((space)->ks_count)
+/** Get the value of the highest key that's been allocated. */
+#define ks_highest(space) ((space)->ks_highest)
+/** Get the maximum number of keys that can be allocated. */
+#define ks_max(space) ((space)->ks_max)
+/** Get the current size of the external array. */
+#define ks_extern(space) ((space)->ks_extern)
+/** Get the chunk size for allocation of the external array. */
+#define ks_chunk(space) ((space)->ks_chunk)
+/** Get the external array growth function callabck. */
+#define ks_grow(space) ((space)->ks_grow)
+/** Get the \a i entry in the keys table. */
+#define ks_keys(space, i) ((space)->ks_keys[(i)])
+/** Get extra data associated with the keyspace. */
+#define ks_extra(space) ((space)->ks_extra)
+
+/** Dynamically initialize a keyspace_t.
+ * @param[in,out] space A pointer to the keyspace_t to be initialized.
+ * @param[in] max Maximum number of keys that can be reserved.
+ * @param[in] chunk Chunk size for calling external routine.
+ * @param[in] grow External routine to call when grown.
+ */
+#define ks_init(space, max, chunk, grow, extra) \
+ do { \
+ keyspace_t* _ks = (space); \
+ _ks->ks_magic = KEYSPACE_MAGIC; \
+ _ks->ks_alloc = 0; \
+ _ks->ks_count = 0; \
+ _ks->ks_highest = 0; \
+ _ks->ks_max = (max); \
+ _ks->ks_extern = 0; \
+ _ks->ks_chunk = (chunk); \
+ _ks->ks_grow = (grow); \
+ _ks->ks_keys = 0; \
+ _ks->ks_extra = (extra); \
+ } while (0)
+
+/* Reserve a key, optionally a specified one. */
+extern key_t ks_reserve(keyspace_t* space);
+
+/* Release an allocated key. */
+extern void ks_release(keyspace_t* space, key_t key);
+
+/* Clean up a keyspace. */
+extern void ks_clean(keyspace_t* space);
+
+#endif /* INCLUDED_keyspace_h */
Property changes on: ircu2/branches/mode/include/keyspace.h
___________________________________________________________________
Added: svn:keywords
+ Id
Modified: ircu2/branches/mode/include/mode.h
===================================================================
--- ircu2/branches/mode/include/mode.h 2008-09-22 16:46:42 UTC (rev 1880)
+++ ircu2/branches/mode/include/mode.h 2008-09-26 04:15:18 UTC (rev 1881)
@@ -28,6 +28,9 @@
#ifndef INCLUDED_flagset_h
#include "flagset.h"
#endif
+#ifndef INCLUDED_keyspace_h
+#include "keyspace.h"
+#endif
struct Client;
struct Channel;
@@ -38,7 +41,7 @@
#define MAX_MODEPARAMS 6
/** Specifies the numerical value of a mode switch. */
-typedef unsigned int mode_t;
+typedef key_t mode_t;
/** Describes a single mode, including parsing flags and policy flags. */
typedef struct ModeDesc mode_desc_t;
@@ -56,7 +59,7 @@
regent_t md_regent; /**< Registration entry. */
int md_switch; /**< Mode switch (character). */
mode_t md_mode; /**< Numerical value of mode. */
- const char *md_desc; /**< Textual description of mode. */
+ const char* md_desc; /**< Textual description of mode. */
flagpage_t md_flags; /**< Flags affecting mode. */
};
@@ -120,8 +123,10 @@
regtab_t ml_table; /**< Registration table. */
size_t ml_offset; /**< Offset of mode structure
within entity. */
- mode_desc_t *ml_smap[256]; /**< Mode switch map. */
- mode_desc_t *ml_mmap[MAX_MODES];
+ keyspace_t* ml_keyspace; /**< Keyspace for mode value
+ allocation. */
+ mode_desc_t* ml_smap[256]; /**< Mode switch map. */
+ mode_desc_t* ml_mmap[MAX_MODES];
/**< Mode value map. */
};
@@ -139,17 +144,17 @@
/** Contains a set of modes with arguments. */
struct ModeArgs {
- mode_args_t *ma_next; /**< Chain to next set of modes with
+ mode_args_t* ma_next; /**< Chain to next set of modes with
arguments. */
- mode_args_t *ma_prev; /**< Chain to previous set of modes
+ mode_args_t* ma_prev; /**< Chain to previous set of modes
with arguments. */
struct {
- mode_desc_t *mam_mode; /**< The mode. */
+ mode_desc_t* mam_mode; /**< The mode. */
mode_dir_t mam_dir; /**< Direction of mode. */
union {
unsigned int mama_int; /**< Unsigned integer argument. */
- const char *mama_str; /**< String argument (keys). */
- struct Client *mama_cli; /**< Client argument (chanops). */
+ const char* mama_str; /**< String argument (keys). */
+ struct Client* mama_cli; /**< Client argument (chanops). */
} mam_arg; /**< Argument for mode. */
unsigned short mam_oplevel; /**< Oplevel for a bounce. */
} ma_modeargs[MAX_MODEPARAMS];
@@ -158,14 +163,14 @@
/** Describes the difference between two mode_set_t's. */
struct ModeDelta {
- struct Client *md_origin; /**< Origin of delta. */
+ struct Client* md_origin; /**< Origin of delta. */
int md_etype; /**< Type of entity--1 for channel,
0 for client. */
union {
- struct Client *mde_client; /**< Client mode delta applies to. */
- struct Channel *mde_chan; /**< Channel mode delta applies to. */
+ struct Client* mde_client; /**< Client mode delta applies to. */
+ struct Channel* mde_chan; /**< Channel mode delta applies to. */
} md_entity; /**< Entity mode delta applies to. */
- mode_list_t *md_modes; /**< Mode list used by this delta. */
+ mode_list_t* md_modes; /**< Mode list used by this delta. */
mode_set_t md_add; /**< Simple modes to be added. */
mode_set_t md_rem; /**< Simple modes to be removed. */
@@ -173,7 +178,7 @@
flagpage_t md_flags; /**< Flags affecting the delta. */
int md_count; /**< Number of modes with args. */
- mode_args_t *md_tail; /**< Tail of modes-with-args list. */
+ mode_args_t* md_tail; /**< Tail of modes-with-args list. */
mode_args_t md_head; /**< First element of modes-with-args
list. */
};
Added: ircu2/branches/mode/ircd/keyspace.c
===================================================================
--- ircu2/branches/mode/ircd/keyspace.c (rev 0)
+++ ircu2/branches/mode/ircd/keyspace.c 2008-09-26 04:15:18 UTC (rev 1881)
@@ -0,0 +1,241 @@
+/*
+ * IRC - Internet Relay Chat, ircd/keyspace.c
+ * Copyright (C) 2008 Kevin L. Mitchell
+ *
+ * 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, 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
+ */
+/** @file
+ * @brief Implementation of allocation of integer keys.
+ * @version $Id$
+ */
+#include "config.h"
+
+#include "keyspace.h"
+#include "flagset.h"
+#include "ircd_alloc.h"
+#include "ircd_log.h"
+
+/** @page keyspace Generic keyspace subsystem.
+ *
+ * @section introkey Introduction
+ *
+ * Many subsystems need to allocate small integers, called \em keys.
+ * These keys are typically used as indexes into an array. This
+ * subsystem is a simple but efficient generic key allocation
+ * subsystem. It is modeled on the pthread_key_create() and
+ * pthread_key_delete() routines, which manage keys for use by the
+ * POSIX functions pthread_getspecific() and pthread_setspecific().
+ * The primary difference between these POSIX interfaces and this
+ * subsystem is that, for the POSIX routines, the key type is opaque,
+ * whereas this subsystem provides simple integers.
+ *
+ * @section keyman Managing Keys
+ *
+ * Keys are represented by the type key_t, and they are allocated from
+ * \a keyspaces, which are specified by a keyspace_t object. This
+ * keyspace_t object must be initialized either with KEYSPACE_INIT()
+ * or ks_init()--the latter allowing for dynamic initialization. Once
+ * keys are allocated, the keyspace_t object will contain some
+ * allocated memory, which may be reclaimed by calling the ks_clean()
+ * routine on the keyspace. Note that the keyspace must be
+ * reinitialized by a call to ks_init() before it can be used again.
+ *
+ * Allocation of a key is simple--simply call the ks_reserve()
+ * function, passing it a pointer to the keyspace. If no more keys
+ * can be allocated--there is a provision for setting the maximum
+ * permissible key--ks_reserve() will return KEY_INVKEY. Otherwise,
+ * it returns a newly allocated key. Allocation is done in a
+ * tight-packed manner, so ks_reserve() may return keys that have been
+ * released. Once you're done with a key, simply call ks_release() to
+ * return it to the system.
+ *
+ * @section advkey Advanced Key Management
+ *
+ * Most subsystems need to maintain an array in conjunction with the
+ * keyspace. This array may contain things such as a pointer to a
+ * function to release whatever object the key is referring to.
+ * Additionally, some subsystems need to impose an upper limit on the
+ * keyspace. Both of these are quite simple to accomplish.
+ *
+ * It is also possible, by specifying a non-zero \a extra argument to
+ * KEYSPACE_INIT() or ks_init(), to associate arbitrary data--such as
+ * a pointer to the externally maintained array--with a keyspace.
+ *
+ * @subsection maxkey Maximum Keys
+ *
+ * Both KEYSPACE_INIT() and ks_init() take an argument called \a max,
+ * which specifies the maximum number of keys that the subsystem can
+ * accommodate. Once that number of keys has been allocated,
+ * ks_reserve() will return KEY_INVKEY until a key has been released
+ * by a call to ks_release(). If an upper limit is unnecessary or
+ * undesired, simply pass 0 for \a max.
+ *
+ * @subsection externkey External Keys
+ *
+ * Managing an external array is also fairly simple to accomplish.
+ * The keyspace subsystem will call a user-defined function whenever a
+ * new key allocation requires that the external array (or whatever
+ * the user is maintaining) needs to be resized. This is accomplished
+ * by specifying the \a chunk and \a grow arguments to KEYSPACE_INIT()
+ * or ks_init(). Both of these arguments must be nonzero in order to
+ * enable this advanced feature.
+ *
+ * The \a grow argument simply specifies a routine that will be called
+ * with a pointer to the keyspace and the new size of the external
+ * array. This new size will be a multiple of the \a chunk size
+ * specified when the keyspace was initialized.
+ *
+ * @section infokey Important Subsystem Information
+ *
+ * This subsystem provides one structure--struct KeySpace--and 2
+ * types: key_t, for the value of keys; and keyspace_t, corresponding
+ * to the struct KeySpace. In particular, keyspace_t should be
+ * treated as opaque by all callers, only referenced through the
+ * provided macros, whereas key_t can be treated as an integral type
+ * suitable for use as an array index.
+ *
+ * This subsystem is intentionally designed to pull in as few other
+ * ircu subsystems as possible, in order to minimize issues with
+ * modularity. It is almost completely self-contained in the
+ * keyspace.h and keyspace.c, referencing the assert() macro in
+ * ircd_log.h and making use of the flagpage_t type and some
+ * associated macros from flagset.h. The subsystem itself needs no
+ * initialization, as all data is completely contained in the
+ * keyspace_t types, which are caller-allocated and initialized.
+ *
+ * This subsystem allocates a small amount of memory for tracking
+ * which keys have been allocated and which ones are available. This
+ * memory is directly associated with the keyspaces that have been
+ * utilized, and may be reclaimed by calling ks_clean() on those
+ * keyspaces.
+ */
+
+/** Allocate a key from a keyspace.
+ * @param[in,out] space The keyspace from which to allocate the key.
+ * @return The reserved key, or #KEY_INVKEY if one could not be allocated.
+ */
+key_t
+ks_reserve(keyspace_t* space)
+{
+ key_t key = KEY_INVKEY;
+
+ assert(KEYSPACE_CHECK(space));
+
+ /* Can we even allocate a key? */
+ if (space->ks_count >= (space->ks_max ? space->ks_max : KEY_INVKEY))
+ return KEY_INVKEY;
+
+ /* Do we need to allocate some more keyspace? */
+ if (space->ks_count == (space->ks_alloc * FLAGSET_NBITS)) {
+ /* resize the key space */
+ space->ks_keys = MyRealloc(space->ks_keys, sizeof(flagpage_t) *
+ (space->ks_alloc + 1));
+
+ /* initialize the new element */
+ space->ks_keys[space->ks_alloc++] = 0;
+
+ /* select a key */
+ key = space->ks_count;
+ } else { /* find an empty slot in the bitmap */
+ flagpage_t alloc, mask = ~0;
+ int i = 0, b = FLAGSET_NBITS >> 1;
+
+ /* search for a page with some unallocated bits */
+ for (; i < space->ks_alloc; i++)
+ if (~space->ks_keys[i]) /* if all bits set, == 0 and we go on */
+ break;
+
+ /* Now, find an unallocated key. This algorithm searches the bit
+ * page specified by i for the first zero bit. (It actually
+ * complements the key page in order to search for the first _set_
+ * bit, which is a slightly easier task.) alloc is the
+ * complemented allocation bitmask, mask is the current testing
+ * mask, b is the number of bits by which to shift the mask, and
+ * key is the resultant index of the first clear bit. The
+ * algorithm works by performing a binary search on the allocation
+ * bitmask: If there are no free bits on the right half, the
+ * allocation bitmask is shifted by the appropriate number of
+ * bits, and then the mask is reduced to half the bits it had
+ * previously. Note that the mask starts off with all bits set,
+ * so the first bitmask update reduces it to half of all bits
+ * set...
+ */
+ for (alloc = ~space->ks_keys[i], key = 0; b; b >>= 1) {
+ mask >>= b; /* update the bitmask... */
+ if (!(alloc & mask)) { /* any clear bits on the right? */
+ alloc >>= b; /* nope, shift over some... */
+ key += b; /* and update the bit count */
+ }
+ }
+
+ /* now correct the key to account for the index i */
+ key += i * FLAGSET_NBITS;
+ }
+
+ /* We have a key, let's mark it set and update some statistics */
+ space->ks_count++;
+ space->ks_keys[FLAGSET_INDEX(key)] |= FLAGSET_MASK(key);
+ if (key > space->ks_highest) {
+ space->ks_highest = key; /* keep track of highest key */
+
+ /* inform the external support of a need to resize */
+ if (space->ks_chunk && space->ks_grow &&
+ space->ks_highest > space->ks_extern)
+ (space->ks_grow)(space, space->ks_extern += space->ks_chunk);
+ }
+
+ /* Return the key */
+ return key;
+}
+
+/** Release a key allocated from a keyspace.
+ * @param[in,out] space The keyspace from which the key was allocated.
+ * @param[in] key The key to release.
+ */
+void
+ks_release(keyspace_t* space, key_t key)
+{
+ assert(KEYSPACE_CHECK(space));
+
+ /* if the key was allocated, mark it free and decrement count */
+ if (space->ks_keys[FLAGSET_INDEX(key)] & FLAGSET_MASK(key)) {
+ space->ks_keys[FLAGSET_INDEX(key)] &= ~FLAGSET_MASK(key);
+ space->ks_count--;
+ }
+}
+
+/** Clean up a keyspace.
+ * @param[in,out] space The key space to clean up.
+ */
+void
+ks_clean(keyspace_t* space)
+{
+ assert(KEYSPACE_CHECK(space));
+
+ /* we're just going to release all keys, so just free the key pages */
+ if (space->ks_keys)
+ MyFree(space->ks_keys);
+
+ /* zero everything */
+ space->ks_magic = 0;
+ space->ks_alloc = 0;
+ space->ks_count = 0;
+ space->ks_highest = 0;
+ space->ks_max = 0;
+ space->ks_extern = 0;
+ space->ks_chunk = 0;
+ space->ks_grow = 0;
+ space->ks_keys = 0;
+}
Property changes on: ircu2/branches/mode/ircd/keyspace.c
___________________________________________________________________
Added: svn:keywords
+ Id
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
_______________________________________________
Patches mailing list
[email protected]
http://undernet.sbg.org/mailman/listinfo/patches