// Copyright (C) 1999-2005 Open Source Telecom Corporation. // // 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. // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. This exception does not however // invalidate any other reasons why the executable file might be covered by // the GNU General Public License. // // This exception applies only to the code released under the name GNU // Common C++. If you copy code from other releases into a copy of GNU // Common C++, as the General Public License permits, the exception does // not apply to the code that you add in this way. To avoid misleading // anyone as to the status of such modified files, you must delete // this exception notice from them. // // If you write modifications of your own for GNU Common C++, it is your choice // whether to permit this exception to apply to your modifications. // If you do not wish that, delete this exception notice. // /** * @file misc.h * @short Memory management, configuration keydata objects and string * tokenizer. **/ #ifndef CCXX_MISC_H_ #define CCXX_MISC_H_ #ifndef CCXX_MISSING_H_ #include #endif #ifndef CCXX_THREAD_H_ #include #endif #define KEYDATA_INDEX_SIZE 97 #define KEYDATA_PAGER_SIZE 512 #if defined(PATH_MAX) #if PATH_MAX > 512 #define KEYDATA_PATH_SIZE 512 #else #define KEYDATA_PATH_SIZE PATH_MAX #endif #else #define KEYDATA_PATH_SIZE 256 #endif #ifdef CCXX_NAMESPACES namespace ost { #endif class __EXPORT Runlist; class __EXPORT Runable; /** * The memory pager is used to allocate cumulative memory pages for * storing object specific "persistant" data that is presumed to persist * during the life of a given derived object. When the object is * destroyed, all accumulated data is automatically purged. * * There are a number of odd and specialized utility classes found in Common * C++. The most common of these is the "MemPager" class. This is basically * a class to enable page-grouped "cumulative" memory allocation; all * accumulated allocations are dropped during the destructor. This class has * found it's way in a lot of other utility classes in Common C++. * * @author David Sugar * @short Accumulative object memory allocator. */ class __EXPORT MemPager { private: friend class String; friend class MemPagerObject; size_t pagesize; unsigned int pages; struct _page { struct _page *next; size_t used; } *page; protected: /** * Allocate first workspace from paged memory. This method * scans all currently allocated blocks for available space * before adding new pages and hence is both slower and more * efficient. * * @param size size of memory to allocate. * @return pointer to allocated memory. */ virtual void* first(size_t size); /** * Allocate memory from either the currently active page, or * allocate a new page for the object. * * @param size size of memory to allocate. * @return pointer to allocated memory. */ virtual void* alloc(size_t size); /** * Allocate a string from the memory pager pool and copy the * string into it's new memory area. This method allocates * memory by first searching for an available page, and then * allocating a new page if no space is found. * * @param str string to allocate and copy into paged memory pool. * @return copy of string from allocated memory. */ char* first(char *str); /** * Allocate a string from the memory pager pool and copy the * string inti it's new memory area. This checks only the * last active page for available space before allocating a * new page. * * @param str string to allocate and copy into paged memory pool. * @return copy of string from allocated memory. */ char* alloc(const char *str); /** * Create a paged memory pool for cumulative storage. This * pool allocates memory in fixed "pagesize" chunks. Ideal * performance is achived when the pool size matches the * system page size. This pool can only exist in derived * objects. * * @param pagesize page size to allocate chunks. */ MemPager(size_t pagesize = 4096); /** * purge the current memory pool. */ void purge(void); /** * Clean for memory cleanup before exiting. */ void clean(void); /** * Delete the memory pool and all allocated memory. */ virtual ~MemPager(); public: /** * Return the total number of pages that have been allocated * for this memory pool. * * @return number of pages allocated. */ inline int getPages(void) {return pages;}; }; /** * The StackPager provides a repository to stash and retrieve working * data in last-in-first-out order. The use of a mempager to support * it's operation allows storage of arbitrary sized objects with no * fixed limit. * * @author David Sugar * @short last in first out object pager. */ class __EXPORT StackPager : protected MemPager { private: typedef struct frame { struct frame *next; char data[1]; } frame_t; frame_t *stack; public: /** * Create a lifo pager as a mempager. * * @param pagesize for memory allocation */ StackPager(size_t pagesize); /** * Push an arbitrary object onto the stack. * * @return stack memory location. * @param object pointer to data * @param size of data. */ void *push(const void *object, size_t size); /** * Push a string onto the stack. * * @return stack memory location. * @param string pointer. */ void *push(const char *string); /** * Retrieve next object from stack. * * @return object. */ void *pull(void); /** * Purge the stack of all objects and memory allocations. */ void purge(void); }; /** * The shared mempager uses a mutex to protect key access methods. * This class is used when a mempager will be shared by multiple * threads. * * @author David Sugar * @short mutex protected memory pager. */ class __EXPORT SharedMemPager : public MemPager, public Mutex { protected: /** * Create a mempager mutex pool. * * @param pagesize page size for allocation. * @param name a name for the pool. */ SharedMemPager(size_t pagesize = 4096, const char *name = NULL); /** * Purge the memory pool while locked. */ void purge(void); /** * Get the first memory page after locking. * * @return allocated memory space. * @param size of request. */ void* first(size_t size); /** * Get the last memory page after locking. * * @return allocated memory space. * @param size of request. */ void* alloc(size_t size); }; __EXPORT void endKeydata(void); /** * Keydata objects are used to load and hold "configuration" data for * a given application. * * This class is used to load and then hold "keyword = value" pairs parsed from a text * based "config" file that has been divided into "[sections]". The syntax is: * *
 * [section_name]
 * key1=value1
 * key2=value2
* * Essentially, the "path" is a "keypath" into a theoretical namespace of key * pairs, hence one does not use "real" filepaths that may be OS dependent. The "/" path refers * to "/etc" prefixed (on UNIX) directories and this is processed within the constructor. It * could refer to the /config prefix on QNX, or even, gasp, a "C:\WINDOWS". Hence, a keypath of * "/bayonne.d/vmhost/smtp" actually resolves to a "/etc/bayonne.d/vmhost.conf" and loads key * value pairs from the [smtp] section of that .conf file. * * Similarly, something like "~bayonne/smtp" path refers to a "~/.bayonnerc" and loads key pairs * from the [smtp] section. This coercion occurs before the name is passed to the open call. * * I actually use derived keydata based classes as global initialized objects, and they hence * automatically load and parse config file entries even before "main" has started. * * Keydata can hold multiple values for the same key pair. This can * occur either from storing a "list" of data items in a config file, * or when overlaying multiple config sources (such as /etc/....conf and * ~/.confrc segments) into a single object. The keys are stored as * cumulative (read-only/replacable) config values under a hash index * system for quick retrieval. * * Keydata can * also load a table of "initialization" values for keyword pairs that were * not found in the external file. * * One typically derives an application specific keydata class to load a * specific portion of a known config file and initialize it's values. One * can then declare a global instance of these objects and have * configuration data initialized automatically as the executable is loaded. * * Hence, if I have a "[paths]" section in a "/etc/server.conf?" file, I might * define something like: * *
 * class KeyPaths : public Keydata
 * {
 *   public:
 *     KeyPaths() : Keydata("/server/paths")
 *     {
 *       static Keydata::Define *defvalues = {
 * 	  {"datafiles", "/var/server"},
 * 	  {NULL, NULL}};
 *
 *       // override with [paths] from "~/.serverrc" if avail.
 *
 *       load("~server/paths");
 *       load(defvalues);
 *     }
 * };
 *
 * KeyPaths keypaths;
 * 
* * @author David Sugar * @short load text configuration files into keyword pairs. */ class __EXPORT Keydata : protected MemPager { public: #ifdef CCXX_PACKED #pragma pack(1) #endif struct Keyval { Keyval *next; char val[1]; }; struct Keysym { Keysym *next; Keyval *data; const char **list; short count; char sym[1]; }; struct Define { char *keyword; char *value; }; #ifdef CCXX_PACKED #pragma pack() #endif private: static std::ifstream *cfgFile; static char lastpath[KEYDATA_PATH_SIZE + 1]; static int count; static int sequence; int link; Keysym *keys[KEYDATA_INDEX_SIZE]; /** * Compute a hash key signature id for a symbol name. * * @return key signature index path. * @param sym symbol name. */ unsigned getIndex(const char *sym); protected: Keysym* getSymbol(const char *sym, bool create); public: /** * Load additional key values into the currrent object from * the specfied config source (a config file/section pair). * These values will overlay the current keywords when matches * are found. This can be used typically in a derived config * object class constructor to first load a /etc section, and * then load a matching user specific entry from ~/. to override * default system values with user specific keyword values. * * @param keypath (filepath/section) */ void load(const char *keypath); /** * Load additional key values into the currrent object from * the specfied config source (a config file/section pair). * These values will overlay the current keywords when matches * are found. This can be used typically in a derived config * object class constructor to first load a /etc section, and * then load a matching user specific entry from ~/. to override * default system values with user specific keyword values. * This varient puts a prefix in front of the key name. * * @param prefix * @param keypath (filepath/section) */ void loadPrefix(const char *prefix, const char *keypath); /** * Load additional keys into the current object using a real * filename that is directly passed rather than a computed key * path. This also uses a [keys] section as passed to the object. * * @param filepath to load from * @param keys section to parse from, or NULL to parse from head * @param pre optional key prefix */ void loadFile(const char *filepath, const char *keys = NULL, const char *pre = NULL); /** * Load default keywords into the current object. This only * loads keyword entries which have not already been defined * to reduce memory usage. This form of Load is also commonly * used in the constructor of a derived Keydata class. * * @param pairs list of NULL terminated default keyword/value pairs. */ void load(Define *pairs); /** * Create an empty key data object. */ Keydata(); /** * Create a new key data object and use "Load" method to load an * initial config file section into it. * * @param keypath (filepath/section) * specifies the home path. */ Keydata(const char *keypath); /** * Alternate constructor can take a define list and an optional * pathfile to parse. * * @param pairs of keyword values from a define list * @param keypath of optional file and section to load from */ Keydata(Define *pairs, const char *keypath = NULL); /** * Destroy the keydata object and all allocated memory. This * may also clear the "cache" file stream if no other keydata * objects currently reference it. */ virtual ~Keydata(); /** * Unlink the keydata object from the cache file stream. This * should be used if you plan to keepa Keydata object after it * is loaded once all keydata objects have been loaded, otherwise * the cfgFile stream will remain open. You can also use * endKeydata(). */ void unlink(void); /** * Get a count of the number of data "values" that is associated * with a specific keyword. Each value is from an accumulation of * "load()" requests. * * @param sym keyword symbol name. * @return count of values associated with keyword. */ int getCount(const char *sym); /** * Get the first data value for a given keyword. This will * typically be the /etc set global default. * * @param sym keyword symbol name. * @return first set value for this symbol. */ const char* getFirst(const char *sym); /** * Get the last (most recently set) value for a given keyword. * This is typically the value actually used. * * @param sym keyword symbol name. * @return last set value for this symbol. */ const char* getLast(const char *sym); /** * Find if a given key exists. * * @param sym keyword to find. * @return true if exists. */ bool isKey(const char *sym); /** * Get a string value, with an optional default if missing. * * @param sym keyword name. * @param default if not present. * @return string value of key. */ const char *getString(const char *sym, const char *def = NULL); /** * Get a long value, with an optional default if missing. * * @param sym keyword name. * @param default if not present. * @return long value of key. */ long getLong(const char *sym, long def = 0); /** * Get a bool value. * * @param sym keyword name. * @return true or false. */ bool getBool(const char *key); /** * Get a floating value. * * @param sym keyword name. * @param default if not set. * @return value of key. */ double getDouble(const char *key, double def = 0.); /** * Get an index array of ALL keywords that are stored by the * current keydata object. * * @return number of keywords found. * @param data pointer of array to hold keyword strings. * @param max number of entries the array can hold. */ unsigned getIndex(char **data, unsigned max); /** * Get the count of keyword indexes that are actually available * so one can allocate a table to receive getIndex. * * @return number of keywords found. */ unsigned getCount(void); /** * Set (replace) the value of a given keyword. This new value * will become the value returned from getLast(), while the * prior value will still be stored and found from getList(). * * @param sym keyword name to set. * @param data string to store for the keyword. */ void setValue(const char *sym, const char *data); /** * Return a list of all values set for the given keyword * returned in order. * * @return list pointer of array holding all keyword values. * @param sym keyword name to fetch. */ const char * const* getList(const char *sym); /** * Clear all values associated with a given keyword. This does * not de-allocate the keyword from memory, however. * * @return keyword name to clear. */ void clrValue(const char *sym); /** * A convient notation for accessing the keydata as an associative * array of keyword/value pairs through the [] operator. */ inline const char *operator[](const char *keyword) {return getLast(keyword);}; /** * static member to end keydata i/o allocations. */ static void end(void); /** * Shutdown the file stream cache. This should be used before * detaching a deamon, exec(), fork(), etc. */ friend inline void endKeydata(void) {Keydata::end();}; }; /** * This class is used to create derived classes which are constructed * within a memory pager pool. * * @short create objects in a memory pager. * @author David Sugar */ class __EXPORT MemPagerObject { public: /** * Allocate memory from a memory pager. * * @param size of new passed from operator. * @param pager to allocate from. */ inline void *operator new(size_t size, MemPager &pager) {return pager.alloc(size);}; /** * Allocate array from a memory pager. * * @param size of new passed from operator. * @param pager to allocate from. */ inline void *operator new[](size_t size, MemPager &pager) {return pager.alloc(size);}; /** * Mempager delete does nothing; the pool purges. */ inline void operator delete(void *) {}; /** * Array mempager delete does nothing; the pool purges. */ inline void operator delete[](void *) {}; }; /** * This class is used to associate (object) pointers with named strings. * A virtual is used to allocate memory which can be overriden in the * derived class. * * @author David Sugar * @short associate names with pointers. */ class __EXPORT Assoc { private: struct entry { const char *id; entry *next; void *data; }; entry *entries[KEYDATA_INDEX_SIZE]; protected: Assoc(); virtual ~Assoc(); void clear(void); virtual void *getMemory(size_t size) = 0; public: void *getPointer(const char *id) const; void setPointer(const char *id, void *data); }; /** * A runlist is used to restrict concurrent exection to a limited set * of concurrent sessions, much like a semaphore. However, the runlist * differs in that it notifies objects when they become ready to run, * rather than requiring them to wait and "block" for the semaphore * count to become low enough to continue. * * @author David Sugar * @short list of runable objects. */ class __EXPORT Runlist : public Mutex { private: Runable *first, *last; protected: unsigned limit, used; void check(void); public: /** * Create a new runlist with a specified limit. * * @param count limit before wait queuing. */ Runlist(unsigned count = 1); /** * Add a runable object to this runlist. If the number of * entries running is below the limit, then add returns true * otherwise the entry is added to the list. * * @return true if immediately ready to run * @param run pointer to runable object. */ bool add(Runable *run); /** * Remove a runable object from the wait list or notify when * it is done running so that the used count can be decremented. * * @param run pointer to runable object. */ void del(Runable *run); /** * Set the limit. * * @param limit to use. */ void set(unsigned limit); }; /** * A container for objects that can be queued against a runlist. * * @author David Sugar * @short runable object with notify when ready. */ class __EXPORT Runable { private: friend class Runlist; Runlist *list; Runable *next, *prev; protected: Runable(); virtual ~Runable(); /** * Method handler that is invoked when a wait-listed object * becomes ready to run. */ virtual void ready(void) = 0; public: /** * Start the object against a run list. * * @return true if immediately available to run. * @param list to start under. */ bool starting(Runlist *list); /** * Stop the object, called when stopping or ready completes. * May also be used for a task that has not yet started to * remove it from the wait list. */ void stoping(void); }; #ifdef CCXX_NAMESPACES } #endif #endif /** EMACS ** * Local variables: * mode: c++ * c-basic-offset: 8 * End: */