summaryrefslogtreecommitdiff
path: root/source4/web_server/ejs/mpr.h
diff options
context:
space:
mode:
Diffstat (limited to 'source4/web_server/ejs/mpr.h')
-rw-r--r--source4/web_server/ejs/mpr.h2259
1 files changed, 2259 insertions, 0 deletions
diff --git a/source4/web_server/ejs/mpr.h b/source4/web_server/ejs/mpr.h
new file mode 100644
index 0000000000..848518befa
--- /dev/null
+++ b/source4/web_server/ejs/mpr.h
@@ -0,0 +1,2259 @@
+///
+/// @file mpr.h
+/// @brief Header for the Mbedthis Portable Runtime (MPR)
+// @copy default
+//
+// Copyright (c) Mbedthis Software LLC, 2003-2005. All Rights Reserved.
+//
+// This software is distributed under commercial and open source licenses.
+// You may use the GPL open source license described below or you may acquire
+// a commercial license from Mbedthis Software. You agree to be fully bound
+// by the terms of either license. Consult the LICENSE.TXT distributed with
+// this software for full details.
+//
+// This software is open source; 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. See the GNU General Public License for more
+// details at: http://www.mbedthis.com/downloads/gplLicense.html
+//
+// This program is distributed WITHOUT ANY WARRANTY; without even the
+// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//
+// This GPL license does NOT permit incorporating this software into
+// proprietary programs. If you are unable to comply with the GPL, you must
+// acquire a commercial license to use this software. Commercial licenses
+// for this software and support services are available from Mbedthis
+// Software at http://www.mbedthis.com
+//
+// @end
+//////////////////////////////// Documentation /////////////////////////////////
+//
+// See mpr.dox for additional documentation.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#error foo
+
+#ifndef _h_MPR
+#define _h_MPR 1
+/////////////////////////////////// Includes ///////////////////////////////////
+
+#include "web_server/ejs/config.h"
+#include "web_server/ejs/mprOs.h"
+
+////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////// C API ////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+#ifdef __cplusplus
+extern "C" {
+#else
+typedef int bool;
+#endif
+
+extern void mprBreakpoint(const char *file, int line, const char *msg);
+
+#if BLD_FEATURE_ASSERT
+#define mprAssert(C) \
+ if (C) ; else mprError(MPR_L, MPR_TRAP, "%s", #C)
+#define inlineAssert(C) \
+ if (C) ; else mprBreakpoint(MPR_L, #C)
+#else
+ #define mprAssert(C) if (1) ; else
+ #define inlineAssert(C) if (1) ; else
+#endif
+
+/////////////////////////////////// Constants //////////////////////////////////
+
+#if BLD_FEATURE_SQUEEZE
+///
+/// Maximum length of a file path name. Reduced from the system maximum to
+/// save memory space.
+///
+#define MPR_MAX_PATH 256 ///< Reasonable max path name
+#else
+#define MPR_MAX_PATH 1024
+#endif
+
+#if BLD_FEATURE_SQUEEZE
+///
+/// Reasonable length of a file name used by the product. Use where you know
+/// the expected file name and it is certain to be less than this limit.
+///
+#define MPR_MAX_FNAME 128 ///< Reasonable size of a file name
+#define MPR_DEFAULT_ALLOC 64 // Default small alloc size
+#define MPR_DEFAULT_HASH_SIZE 23 // Default size of hash table index
+#define MPR_DEFAULT_STACK (32 * 1024) // Default stack size
+#else
+#define MPR_MAX_FNAME 256
+#define MPR_DEFAULT_ALLOC 128 // Default small alloc size
+#define MPR_DEFAULT_HASH_SIZE 43 // Default size of hash table index
+#define MPR_DEFAULT_STACK (64 * 1024) // Default stack size
+#endif
+
+#if BLD_FEATURE_SQUEEZE
+#define MPR_MAX_ARGC 32 // Reasonable max of args
+#define MPR_MAX_STRING 512 // Maximum string size
+#define MPR_MAX_LOG_STRING 512 // Maximum log message
+#define MPR_MAX_URL 256 ///< Reasonable size of a URL
+#define MPR_BUFSIZE 512 ///< Reasonable size for buffers
+// FUTURE -- could be named better
+#define MPR_MAX_HEAP_SIZE (32 * 1024) // Maximum heap allocation size
+#else
+#define MPR_MAX_ARGC 128 // Reasonable max of args
+#define MPR_MAX_STRING 4096 ///< Maximum string size
+#define MPR_MAX_LOG_STRING 8192 // Maximum log message
+#define MPR_MAX_URL 1024 ///< Reasonable size of a URL
+#define MPR_BUFSIZE 1024 // Reasonable size for buffers
+#define MPR_MAX_HEAP_SIZE (64 * 1024) // Maximum heap allocation size
+#endif
+
+#define MPR_DEFAULT_BREAK_PORT 9473
+#define MPR_TIMEOUT_LOG_STAMP 3600000 // Time between log time stamps
+#define MPR_TIMEOUT_PRUNER 60000 // Time between pruner runs
+#define MPR_TIMEOUT_STOP_TASK 10000 // Timeout to stop running tasks
+#define MPR_TIMEOUT_STOP_THREAD 10000 // Timeout to stop running threads
+#define MPR_TIMEOUT_CMD_WAIT 50 // Poll for cmd processes
+#define MPR_TIMEOUT_STOP 5000 // Wait when stopping resources
+#define MPR_NUM_DIALOG 5 // Maximum number of user dialogs
+#define MPR_MAX_LOG_SIZE 5 // Default size of a log file (MB)
+#define MPR_MAX_IP_NAME 128 // Max size of an IP name
+#define MPR_MAX_IP_ADDR 16 // Max size of an IP string addr
+#define MPR_MAX_IP_ADDR_PORT 32 // Max size of IP with port
+
+#define MPR_TEST_TIMEOUT 10000 // Ten seconds
+#define MPR_TEST_LONG_TIMEOUT 300000 // 5 minutes
+#define MPR_TEST_SHORT_TIMEOUT 200 // 1/5 sec
+#define MPR_TEST_NAP 50 // When we must not block
+
+#if BLD_FEATURE_MULTITHREAD
+#define MPR_DEFAULT_MIN_THREADS 0 // Default min threads (0)
+#define MPR_DEFAULT_MAX_THREADS 10 // Default max threads (10)
+#else
+#define MPR_DEFAULT_MIN_THREADS 0 // Default min threads
+#define MPR_DEFAULT_MAX_THREADS 0 // Default max threads
+#endif
+
+//
+// MPR priorities (0 to 99)
+//
+#define MPR_BACKGROUND_PRIORITY 15 // May only get CPU if idle
+#define MPR_LOW_PRIORITY 25
+#define MPR_NORMAL_PRIORITY 50
+#define MPR_HIGH_PRIORITY 75
+#define MPR_CRITICAL_PRIORITY 99 // May not yield
+
+#define MPR_SELECT_PRIORITY 75 // Run select at higher priority
+#define MPR_POOL_PRIORITY 50 // Normal
+
+//
+// Debug control
+//
+#define MPR_MAX_BLOCKED_LOCKS 100 // Max threads blocked on lock
+#define MPR_MAX_RECURSION 15 // Max recursion with one thread
+#define MPR_MAX_LOCKS 512 // Total lock count max
+#define MPR_MAX_LOCK_TIME (60 * 1000) // Time in millisecs to hold a lock
+
+//
+// Service / daemon control
+//
+#define MPR_INSTALL_SERVICE 1
+#define MPR_UNINSTALL_SERVICE 2
+#define MPR_GO_SERVICE 3
+#define MPR_STOP_SERVICE 4
+
+//
+// Parameter values for serviceEvents(loopOnce)
+//
+#define MPR_LOOP_ONCE 1
+#define MPR_LOOP_FOREVER 0
+
+//
+// Select service flags
+//
+#define MPR_ASYNC_SELECT 0x1 // Using async select in windows
+#define MPR_BREAK_REQUESTED 0x2 // Breakout of a select wait
+#define MPR_WAITING_FOR_SELECT 0x4 // Waiting for select to complete
+
+///////////////////////////////// Error Codes //////////////////////////////////
+
+//
+// Standard MPR return and error codes
+//
+
+/// Base error code
+#define MPR_ERR_BASE (-200)
+/// General error
+#define MPR_ERR_GENERAL (MPR_ERR_BASE - 1)
+/// Action aborted
+#define MPR_ERR_ABORTED (MPR_ERR_BASE - 2)
+/// Item already exists
+#define MPR_ERR_ALREADY_EXISTS (MPR_ERR_BASE - 3)
+/// Bad arguments or paramaeters
+#define MPR_ERR_BAD_ARGS (MPR_ERR_BASE - 4)
+/// Bad input format
+#define MPR_ERR_BAD_FORMAT (MPR_ERR_BASE - 5)
+#define MPR_ERR_BAD_HANDLE (MPR_ERR_BASE - 6)
+/// Module is in a bad state
+#define MPR_ERR_BAD_STATE (MPR_ERR_BASE - 7)
+/// Input has bad syntax
+#define MPR_ERR_BAD_SYNTAX (MPR_ERR_BASE - 8)
+#define MPR_ERR_BAD_TYPE (MPR_ERR_BASE - 9)
+#define MPR_ERR_BAD_VALUE (MPR_ERR_BASE - 10)
+#define MPR_ERR_BUSY (MPR_ERR_BASE - 11)
+/// Cant access the file or resource
+#define MPR_ERR_CANT_ACCESS (MPR_ERR_BASE - 12)
+#define MPR_ERR_CANT_COMPLETE (MPR_ERR_BASE - 13)
+/// Cant create the file or resource
+#define MPR_ERR_CANT_CREATE (MPR_ERR_BASE - 14)
+#define MPR_ERR_CANT_INITIALIZE (MPR_ERR_BASE - 15)
+/// Cant open the file or resource
+#define MPR_ERR_CANT_OPEN (MPR_ERR_BASE - 16)
+/// Cant read from the file or resource
+#define MPR_ERR_CANT_READ (MPR_ERR_BASE - 17)
+/// Cant write to the file or resource
+#define MPR_ERR_CANT_WRITE (MPR_ERR_BASE - 18)
+#define MPR_ERR_DELETED (MPR_ERR_BASE - 19)
+#define MPR_ERR_NETWORK (MPR_ERR_BASE - 20)
+#define MPR_ERR_NOT_FOUND (MPR_ERR_BASE - 21)
+/// Module or resource is not initialized
+#define MPR_ERR_NOT_INITIALIZED (MPR_ERR_BASE - 22)
+#define MPR_ERR_NOT_READY (MPR_ERR_BASE - 23)
+#define MPR_ERR_READ_ONLY (MPR_ERR_BASE - 24)
+/// The operation timed out
+#define MPR_ERR_NOT_INITIALIZED (MPR_ERR_BASE - 22)
+#define MPR_ERR_TIMEOUT (MPR_ERR_BASE - 25)
+#define MPR_ERR_TOO_MANY (MPR_ERR_BASE - 26)
+#define MPR_ERR_WONT_FIT (MPR_ERR_BASE - 27)
+#define MPR_ERR_WOULD_BLOCK (MPR_ERR_BASE - 28)
+#define MPR_ERR_CANT_ALLOCATE (MPR_ERR_BASE - 29)
+#define MPR_ERR_MAX (MPR_ERR_BASE - 30)
+
+//
+// Standard error severity and trace levels. These are ored with the error
+// severities below. The MPR_LOG_MASK is used to extract the trace level
+// from a flags word. We expect most apps to run with level 2 trace.
+//
+#define MPR_FATAL 0 ///< Fatal error trace level. Cant continue.
+#define MPR_ERROR 1 ///< Hard error trace level
+#define MPR_WARN 2 ///< Soft warning trace level
+#define MPR_CONFIG 2 ///< Configuration settings trace level.
+#define MPR_INFO 3 ///< Informational trace only
+#define MPR_DEBUG 4 ///< Debug information trace level
+#define MPR_VERBOSE 9 ///< Highest level of trace
+#define MPR_LOG_MASK 0xf ///< Level mask
+
+//
+// Error flags. Specify where the error should be sent to. Note that the
+// product.xml setting "headless" will modify how errors are reported.
+// Assert errors are trapped when in DEV mode. Otherwise ignored.
+//
+#define MPR_TRAP 0x10 // Assert mprError flags -- trap in debugger
+#define MPR_LOG 0x20 ///< Log to the O/S event log mprError flag
+#define MPR_USER 0x40 ///< Display to the user mprError flag
+#define MPR_ALERT 0x80 // Send a management alert
+#define MPR_TRACE 0x100 // Trace
+
+//
+// Error format flags
+//
+#define MPR_RAW 0x200 // Raw trace output
+
+//
+// Error line number information
+//
+#define MPR_L __FILE__, __LINE__
+
+////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// Function Remappings ////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Unsafe functions that should not be used. Define UNSAFE_STRINGS_OK before
+// including mpr.h if you really want to use these functions. A better approach
+// is to undefine them just prior to using them in your C/C++ source file.
+//
+#if BLD_FEATURE_SAFE_STRINGS
+
+#if BLD_FEATURE_PHP4_MODULE || BLD_FEATURE_PHP5_MODULE
+#ifndef UNSAFE_FUNCTIONS_OK
+#define UNSAFE_FUNCTIONS_OK 1
+#endif
+#endif
+
+#ifndef UNSAFE_FUNCTIONS_OK
+#define sprintf UseMprSprintfInstead
+#define printf UseMprPrintfInstead
+#define fprintf UseMprFprintfInstead
+#define vsprintf UseMprVsprintfInstead
+#define strtok UseMprStrTokInstead
+#define gethostbyname UseMprGetHostByNameInstead
+#define ctime UseMprCtimeInstead
+#define asctime UseMprAsctimeInstead
+#define localtime UseMprLocaltimeInstead
+#define gmtime UseMprGmtimeInstead
+#define malloc UseMprMallocInstead
+#define free UseMprFreeInstead
+#define realloc UseMprReallocInstead
+#define calloc UseMprCallocInstead
+#define strncpy UseMprStrcpyInstead
+#define inet_ntoa UseMprInetNtoaInstead
+
+//
+// FUTURE -- to the whole way
+//
+//#define strlen UseMprStrlenInstead
+//#define strcpy UseMprStrcpyInstead
+
+#endif // UNSAFE_FUNCTIONS_OK
+#endif // BLD_FEATURE_SAFE_STRINGS
+
+//
+// File information structure
+//
+struct MprFileInfo {
+ uint size; // File length
+ uint mtime; // Modified time
+ uint inode; // Inode number
+ bool isDir; // Set if directory
+ bool isReg; // Set if a regular file
+};
+
+//
+// Mpr time structure. Used for mprGetTime(). Matches requirements of select().
+//
+struct MprTime {
+ long sec; // Seconds
+ long usec; // Microseconds (NOT milliseconds)
+};
+typedef struct MprTime MprTime;
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////// C++ APIs ///////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+#if __cplusplus
+
+class MprBuf;
+class MprFile;
+class MprFileSystem;
+class MprHashTable;
+class MprLink;
+class MprList;
+class MprPoolService;
+class MprPoolThread;
+class MprSelectService;
+class MprSelectHandler;
+class MprSocket;
+class MprSocketService;
+class MprStringData;
+class MprStringList;
+class MprTask;
+class MprTimerService;
+class MprTimer;
+
+#if BLD_FEATURE_LOG
+class MprLogModule;
+class MprLogService;
+class MprLogListener;
+class MprLogToFile;
+class MprLogToWindow;
+#endif
+
+#if BLD_FEATURE_CGI_MODULE
+class MprCmd;
+class MprCmdFiles;
+class MprCmdService;
+#endif
+
+#if BLD_FEATURE_MULTITHREAD
+class MprCond;
+class MprMutex;
+class MprThreadService;
+class MprThread;
+#else
+typedef void *MprMutex;
+#endif
+
+#if BLD_FEATURE_RUN_AS_SERVICE && WIN
+class MprWinService;
+#endif
+
+/////////////////////////////////// MprLink ////////////////////////////////////
+
+//
+// This define is used by classes that include a Link field member, to get
+// the base class pointer
+//
+#define MPR_GET_BASE(type, ptr, field) \
+ ((type) ((int) ptr - ((int) &(((type) 1)->field) - (int) ((type) 1))))
+
+//
+// The MprLink class enables subclassed objects to be inserted in a MprList. It
+// provides forward and back links for fast insertion, removal and iteration.
+// To use MprLink, subclasses must inherit MprLink as a base class. Use
+// MprList for the dummy list header and MprLink for the list members.
+// This class is NOT thread-safe. Callers must do their own thread
+// synchronization. It is designed to be "inline", very fast and no-frills.
+//
+
+class MprLink {
+ // FUTURE -- revert to protected
+ public:
+ MprLink *next; // Ptr to next member in list
+ MprLink *prev; // Ptr to prev member in list
+ MprList *head; // Ptr to the list head
+
+ public:
+ MprLink() { ///< Constructor
+ next = prev = this;
+ head = 0;
+ };
+ ~MprLink() {}; ///< Destructor
+ MprList *getList() { return head; };///< Return the owning list
+
+ inline void insertAfter(MprLink *item); ///< Insert after this member
+ inline void insertPrior(MprLink *item); ///< Insert prior to this member
+};
+
+/////////////////////////////////// MprList ////////////////////////////////////
+//
+// The MprList class defines the list (dummy) header for doubly linked objects.
+// It provides forward and back links for fast insertion, removal and
+// iteration. To use MprLink, subclasses must inherit MprLink as a base class.
+// Use MprList for the dummy list header and MprLink for the list members.
+// This class is NOT thread-safe. Callers must do their own thread
+// synchronization. It is designed to be "inline", very fast and no-frills.
+//
+
+class MprList : public MprLink {
+ protected:
+ int numItems; // Number of items in the list
+
+ public:
+ MprList() {
+ numItems = 0;
+ head = this;
+ next = prev = this;
+ };
+ ~MprList() {
+ };
+ inline void insert(MprLink *item) { /// Add to the end of the list
+ inlineAssert(item->head == 0);
+ if (item->head == 0) {
+ numItems++;
+ }
+ item->head = this;
+ item->next = head;
+ item->prev = head->prev;
+ prev->next = item;
+ prev = item;
+ };
+ inline MprLink *remove(MprLink *item) { /// Remove this item
+ inlineAssert(item->head == this);
+ item->next->prev = item->prev;
+ item->prev->next = item->next;
+ item->prev = 0;
+ item->next = 0;
+ inlineAssert(numItems > 0);
+ if (item->head == head) {
+ numItems--;
+ }
+ item->head = 0;
+ return next;
+ };
+ inline MprLink *getFirst() { /// Get first item
+ return (next == head) ? 0 : next;
+ };
+ inline MprLink *getLast() { /// Get last item
+ return (next == head) ? 0 : prev;
+ };
+ inline MprLink *getNext(MprLink *item) { /// Get next item
+ inlineAssert(item->head == this);
+ return (item->next == head) ? 0 : item->next;
+ };
+ inline MprLink *getPrev(MprLink *item) { /// Get previous item
+ inlineAssert(item->head == this);
+ return (item->prev == head) ? 0 : item->prev;
+ };
+ int getNumItems() { /// Get number of items.
+ return numItems;
+ };
+ bool emptyOk() {
+ if ((head == this) && (next == head) &&
+ (prev == head) && (numItems == 0)) {
+ return 1;
+ } else {
+ return 0;
+ }
+ };
+
+ friend class MprLink;
+};
+
+//
+// Inline methods for MprLink
+//
+inline void MprLink::insertAfter(MprLink *item) {
+ inlineAssert(item->head == 0);
+ item->head = head;
+ next->prev = item;
+ item->prev = this;
+ item->next = next;
+ next = item;
+ head->numItems++;
+ };
+inline void MprLink::insertPrior(MprLink *item) {
+ inlineAssert(item->head == 0);
+ item->head = head;
+ prev->next = item;
+ item->next = this;
+ item->prev = prev;
+ prev = item;
+ head->numItems++;
+ };
+
+//////////////////////////////// MprStringList /////////////////////////////////
+
+class MprStringData : public MprLink {
+ public:
+ MprStr string;
+
+ public:
+ MprStringData(char *s);
+ ~MprStringData();
+ inline char *getValue() { return string; };
+};
+
+class MprStringList : public MprList {
+ public:
+ MprStringList(char *str);
+ MprStringList();
+ ~MprStringList();
+ void insert(char *str);
+ void parse(char *str);
+};
+
+////////////////////////////////// MprCmdLine //////////////////////////////////
+
+class MprCmdLine {
+ private:
+ int argc;
+ char **argv; // Not duped
+ void *argvBuf; // Storage for argv and args
+ bool inSwitch;
+ int optc;
+ int optind;
+ char *switches; // Not duped
+
+ public:
+ MprCmdLine(int argc, char **argv, char *switches);
+ MprCmdLine(char *args, char *switches);
+ ~MprCmdLine();
+ char **getArgv() { return argv; };
+ int getArgc() { return argc; };
+ int next(char **argp = 0);
+ int firstArg();
+};
+
+/////////////////////////////////// MprCond ////////////////////////////////////
+#if BLD_FEATURE_MULTITHREAD
+
+//
+// Condition variable for multi-thread synchronization
+//
+// Condition variables can be used to coordinate threads when running in a
+// multi-threaded mode. These condition variables are level triggered in that
+// a condition can be signalled prior to another thread waiting. That thread
+// will then not block if it calls waitForCond().
+//
+
+class MprCond {
+ private:
+ #if BLD_DEBUG
+ //
+ // This must be the first item in the class
+ //
+ MprLink link; // Cond-var leak monitoring
+ #endif
+ #if LINUX || MACOSX || SOLARIS
+ pthread_cond_t
+ cv; // Pthreads condition variable
+ #endif
+ #if WIN
+ HANDLE cv; // Windows event handle
+ int numWaiting; // Number waiting to be signalled
+ #endif
+ #if VXWORKS
+ SEM_ID cv; // Condition variable
+ #endif
+ MprMutex *mutex; // Thread sync
+ int triggered; // Value of the condition
+
+#if UNUSED
+ int wakeAll; // Wake all waiters on signalCond()
+#endif
+
+ public:
+ MprCond();
+ ~MprCond();
+ int waitForCond(long timeout = -1);
+ void signalCond();
+
+#if UNUSED
+ int multiWait(MprMutex *externalMutex, long timeout = -1);
+ void reset();
+ void signalAll();
+#endif
+};
+
+#endif // BLD_FEATURE_MULTITHREAD
+/////////////////////////////////// MprDebug ///////////////////////////////////
+#if BLD_DEBUG
+
+class MprDebug {
+ public:
+#if BLD_FEATURE_MULTITHREAD
+ int getMutexNum();
+#endif
+};
+
+#endif
+/////////////////////////////////// MprFile ////////////////////////////////////
+
+class MprFile {
+ private:
+ MprBuf *inBuf;
+ int fd;
+ public:
+ MprFile();
+ virtual ~MprFile();
+ virtual int open(char* path, int flags, int mode);
+ virtual void close();
+ virtual char *gets(char *buf, int len);
+ virtual int read(void* buf, int len);
+ virtual int write(void* buf, int len);
+ virtual long lseek(long offset, int origin);
+};
+
+//////////////////////////////// MprFileSystem /////////////////////////////////
+
+class MprFileSystem {
+ private:
+ public:
+ MprFileSystem();
+ virtual ~MprFileSystem();
+ virtual MprFile *newFile();
+ virtual int stat(char* path, MprFileInfo* info);
+ virtual bool isDir(char* path);
+ virtual void setRoot(char* path);
+};
+
+/////////////////////////////////// MprMutex ///////////////////////////////////
+#if BLD_FEATURE_MULTITHREAD
+
+//
+// Mutual exclusion locks
+//
+class MprMutex {
+ public:
+ #if BLD_DEBUG
+ MprLink link; // Must be the first in the class
+ #endif
+ #if WIN
+ CRITICAL_SECTION cs; // O/S critical section
+ #endif
+ #if LINUX || MACOSX || SOLARIS
+ pthread_mutex_t cs; // O/S critical section
+ #endif
+ #if VXWORKS
+ SEM_ID cs; // Semaphore
+ #endif
+
+ public:
+ MprMutex();
+ ~MprMutex();
+ int tryLock();
+
+ // FUTURE -- should do Windows inline also.
+
+ #if LINUX || MACOSX || SOLARIS
+ inline void lock() { pthread_mutex_lock(&cs); };
+ inline void unlock() { pthread_mutex_unlock(&cs); };
+ #elif VXWORKS && 0
+ inline void lock() { semTake(cs, WAIT_FOREVER); };
+ inline void unlock() { semGive(cs); };
+ #else
+ void lock();
+ void unlock();
+ #endif
+
+ friend class MprCond;
+};
+
+#endif // BLD_FEATURE_MULTITHREAD
+////////////////////////////////////// Mpr /////////////////////////////////////
+//
+// Mpr flags
+//
+#define MPR_EXITING 0x1 // Mpr is exiting
+#define MPR_ASYNC_SELECTING 0x2 // Using async select
+#define MPR_HEADLESS 0x4 // No user interface
+#define MPR_SERVICE_THREAD 0x10 // Using a service thread for events
+#define MPR_IS_DAEMON 0x20 // Is a daemon / service
+#define MPR_STOPPED 0x40 // Mpr services stopped
+#define MPR_STARTED 0x80 // Mpr services started
+#define MPR_KILLABLE 0x100 // MPR can be killed (need a pid file)
+#define MPR_USER_START_FLAGS (MPR_SERVICE_THREAD | MPR_KILLABLE)
+
+typedef int (*MprDllEntryProc)(void *arg);
+
+//
+// The Mbedthis Portable Runtime (MPR) internal state class.
+//
+class Mpr {
+ private:
+ MprStr appName; // One word name of the application
+ MprStr appTitle; // Displayable name of the product
+ int buildNumber; // Build number
+ MprStr buildType; // Build type
+ MprHashTable *configSettings; // Configuration settings for app
+ MprStr cpu; // Procesor
+ MprStr domainName; // Domain portion
+ MprStr hostName; // Host name (fully qualified name)
+ MprStr installDir; // Installation directory (!= cwd)
+ MprStr os; // Operating system
+ MprStr serverName; // Server name portion (no domain)
+ MprStr version; // Application version number (x.y.z)
+
+ //
+ // FUTURE -- Convert to flags
+ //
+ int flags; // Processing state
+ int headless; // Run headless
+ bool runAsService; // Running as a service (daemon)
+ bool eventsThread; // Running an events thread
+
+#if WIN
+ long appInstance; // Application instance (windows)
+ HWND hwnd; // Window handle
+#endif
+
+#if BLD_FEATURE_LOG
+ MprLogModule *defaultLog; // Default log module
+#endif
+
+#if BLD_FEATURE_MULTITHREAD
+ MprMutex *mutex; // Thread synchronization
+ MprMutex *timeMutex; // Thread sync for mprGetTime
+ MprMutex *eventsMutex; // Thread sync for serviceEvents
+#endif
+
+ public:
+#if BLD_FEATURE_LOG
+ MprLogService *logService; // Log service object
+#endif
+ MprPoolService *poolService; // Pool service object
+ MprSelectService *selectService; // Select service object
+ MprSocketService *socketService; // MprSocket service object
+ MprTimerService *timerService; // Timer service object
+ MprList modules; // List of modules
+
+#if BLD_FEATURE_CGI_MODULE
+ MprCmdService *cmdService; // Run command service object
+#endif
+#if BLD_FEATURE_MULTITHREAD
+ MprThreadService *threadService; // Thread service object
+#endif
+
+ public:
+ //
+ // Published API
+ //
+ Mpr(char *appName);
+ ~Mpr();
+#if BLD_FEATURE_LOG
+ void addListener(MprLogListener *lp);
+#endif
+ bool getAsyncSelectMode();
+ int getIdleTime();
+ bool isExiting(void);
+ int runTasks();
+ int runTimers();
+ void serviceEvents(bool loopOnce, int maxTimeout);
+ void setAsyncSelectMode(bool on);
+ int setLogSpec(char *spec);
+ int start(int startFlags = 0);
+ int stop(bool immediateStop);
+ void terminate(bool graceful = 1);
+#if WIN
+ void setHwnd(HWND appHwnd);
+ void setSocketHwnd(HWND socketHwnd);
+ void setSocketMessage(int msgId);
+#endif
+
+ //
+ // Unpublished API
+ //
+
+ int configure(char *configFile);
+ char *getAppName(void);
+ char *getAppTitle(void);
+ int getBuildNumber(void);
+ char *getBuildType(void);
+ char *getCpu(void);
+ char *getDomainName(void);
+ int getFds(fd_set *readInterest, fd_set *writeInterest,
+ fd_set *exceptInterest, int *maxFd, int *lastGet);
+ int getHeadless(void);
+ char *getHostName(void);
+ char *getInstallDir(void);
+ char *getOs(void);
+ char *getServerName(void);
+ char *getVersion(void);
+ bool isRunningEventsThread() { return eventsThread; };
+ bool isService();
+ int killMpr();
+ int makeDaemon(int parentExit);
+ void serviceIO(int readyFds, fd_set *readFds, fd_set *writeFds,
+ fd_set *exceptFds);
+ void serviceIO(int sockFd, int winMask);
+ void setAppName(char *name);
+ void setAppTitle(char *name);
+ void setBuildNumber(int buildNumber);
+ void setBuildType(char *type);
+ void setCpu(char *cpu);
+ void setDomainName(char *host);
+ void setHeadless(int headless);
+ void setHostName(char *host);
+ void setInstallDir(char *dir);
+ void setOs(char *os);
+ void setPriority(int pri);
+ void setServerName(char *host);
+ void setService(bool service);
+ void setVersion(char *version);
+ void setWebServerAddress(char *path);
+ void writeToOsLog(char *msg, int etype);
+
+#if BLD_FEATURE_MULTITHREAD
+ void startEventsThread();
+ void setMinPoolThreads(int n);
+ void setMaxPoolThreads(int n);
+ int getMinPoolThreads();
+ int getMaxPoolThreads();
+ int getNextThreadNum();
+ MprThread *getCurrentThread();
+ inline void lock() {
+ if (mutex) {
+ mutex->lock();
+ }
+ };
+ inline void unlock() {
+ if (mutex) {
+ mutex->unlock();
+ }
+ };
+ void timeLock() { timeMutex->lock(); };
+ void timeUnlock() { timeMutex->unlock(); };
+#else
+ int getMaxPoolThreads() { return 0; };
+ inline void lock() {};
+ inline void unlock() {};
+ inline void timeLock() {};
+ inline void timeUnlock() {};
+#endif
+
+#if WIN
+ HWND getHwnd();
+ long getInst();
+ void setInst(long inst);
+#endif
+
+#if BLD_FEATURE_DLL
+ int loadDll(char *path, char *fnName, void *arg, void **handle);
+ void unloadDll(void *handle);
+#endif
+
+#if BLD_FEATURE_XML_CONFIG
+ int openConfigFile(char *path);
+ int openXmlFile(char *path);
+ int readXmlInt(MprHashTable *symTab, char *key, int *value);
+ int readXmlStr(MprHashTable *symTab, char *key, char **value);
+#endif
+ char *getConfigStr(char *key, char *defaultValue);
+ int getConfigInt(char *key, int defaultValue);
+
+#if BLD_FEATURE_CGI_MODULE
+ MprCmdService *getCmdService() { return cmdService; };
+#endif
+
+ private:
+ int platformInitialize();
+ int platformTerminate();
+ int platformStart(int startFlags);
+ int platformStop();
+};
+
+#if MPR_IN_MPR
+extern Mpr *mpr; // Default global Mpr class
+#endif
+
+extern Mpr *mprGetMpr();
+
+//////////////////////////////// MprHashEntry //////////////////////////////////
+//
+// Master hash entry type. Not thread safe.
+//
+
+class MprHashEntry : public MprLink {
+ private:
+ MprStr key;
+ MprList *bucket;
+
+ public:
+ MprHashEntry();
+ MprHashEntry(char *key);
+ virtual ~MprHashEntry();
+ char *getKey();
+ void setKey(char *key);
+ friend class MprHashTable;
+};
+
+//
+// String entry type
+//
+class MprStringHashEntry : public MprHashEntry {
+ private:
+ MprStr value;
+ public:
+ MprStringHashEntry(char *key, char *str);
+ virtual ~MprStringHashEntry();
+ char *getValue() { return value; };
+};
+
+//
+// Static string (not duplicated)
+//
+class MprStaticHashEntry : public MprHashEntry {
+ private:
+ char *value;
+ public:
+ MprStaticHashEntry(char *key, char *str);
+ virtual ~MprStaticHashEntry();
+ char *getValue() { return value; };
+};
+
+#if PERHAPS
+//
+// Object string (not duplicated)
+//
+class MprObjectHashEntry : public MprHashEntry {
+ private:
+ char *value;
+ public:
+ MprObjectHashEntry(char *key, char *str);
+ virtual ~MprObjectHashEntry();
+ char *getValue() { return value; };
+};
+#endif
+
+///////////////////////////////// MprHashTable /////////////////////////////////
+
+class MprHashTable {
+ private:
+ MprList *buckets;
+ int size;
+ int count;
+
+ public:
+ MprHashTable(int hash_size = MPR_DEFAULT_HASH_SIZE);
+ ~MprHashTable();
+ MprHashEntry *getFirst();
+ MprHashEntry *getNext(MprHashEntry *ep);
+ int getNumItems() { return count; };
+ int insert(MprHashEntry *entry);
+ MprHashEntry *lookup(char *key);
+ int remove(char *key);
+ int remove(MprHashEntry *entry);
+ int removeAll();
+
+ private:
+ MprHashEntry *lookupInner(char *key, MprList **bucket);
+ int hashIndex(char *key);
+ int getNextPrime(int size);
+};
+
+//////////////////////////////// MprLogService /////////////////////////////////
+#if BLD_FEATURE_LOG
+
+class MprLogListener : public MprLink {
+ private:
+ int maxSize; // Max size of log
+ public:
+ //
+ // Published API
+ //
+ MprLogListener(); ///< Constructor
+ virtual ~MprLogListener(); ///< Destructor
+ virtual void logEvent(char *module, int flags, int level, char *thread,
+ char *msg);
+ virtual int start();
+
+ //
+ // Unpublished API
+ //
+ virtual void shuttingDown();
+ virtual int setLogSpec(char *path, int maxSize);
+ virtual void stop();
+};
+
+
+class MprLogToFile : public MprLogListener {
+ private:
+ int logFd; // MprLogService file handle
+ MprStr logFileName; // Current name of log file
+ bool timeStamps; // Output high res time stamps
+ uint maxSize; // Maximum extent of trace file
+ int rotationCount; // Number of times logs rotated
+ MprTimer *timer; // Log file time stamp timer
+ public:
+ MprLogToFile(); ///< Constructor
+ ~MprLogToFile(); ///< Destructor
+ void logEvent(char *module, int flags, int level, char *thread,
+ char *msg);
+ void enableTimeStamps(bool on);
+ void logConfig();
+ void rotate();
+ void shuttingDown();
+ int setLogSpec(char *path, int maxSize);
+ int start();
+ void stop();
+ void writeTimeStamp();
+};
+
+
+class MprLogToWindow : public MprLogListener {
+ private:
+ public:
+ MprLogToWindow(); ///< Constructor
+ ~MprLogToWindow(); ///< Destructor
+ void logEvent(char *module, int flags, int level, char *thread,
+ char *msg);
+};
+
+
+//
+// Overall logging service
+//
+class MprLogService {
+ private:
+ MprList listeners; // Users registered for output
+ uint defaultLevel; // Default level for modules
+ MprLogModule *defaultModule; // Default log module for this log
+ MprList moduleList; // List of modules to trace
+ char *moduleSpecs; // Module level spec string
+ char *logSpec; // Saved logging spec string
+ bool logging; // Logging is enabled
+#if BLD_FEATURE_MULTITHREAD
+ MprMutex *mutex; // Mutex lock
+#endif
+
+ public:
+ MprLogService();
+ ~MprLogService(void);
+ void addListener(MprLogListener *lp);
+ void insertModule(MprLogModule *module);
+ void error(char *file, int line, int flags, char *fmt,
+ va_list args);
+ MprLogModule *getDefaultModule() { return defaultModule; };
+ int getDefaultLevel() { return defaultLevel; };
+ char *getLogSpec() { return logSpec; };
+ char *getModuleSpecs();
+ bool isLogging();
+ void removeListener(MprLogListener *lp);
+ void removeModule(MprLogModule *module);
+ void setDefaultLevel(int l);
+ void setDefaultModule(MprLogModule *m) { defaultModule = m; };
+ int setLogSpec(char *fileSpec);
+ void shuttingDown();
+ void start();
+ void stop();
+ void traceCore(int level, int flags, MprLogModule *module,
+ char *fmt, va_list ap);
+ void writeHeader();
+ void writeLogStamp();
+
+#if BLD_FEATURE_MULTITHREAD
+ void lock() {
+ if (mutex) {
+ mutex->lock();
+ }
+ };
+ void unlock() {
+ if (mutex) {
+ mutex->unlock();
+ }
+ };
+#else
+ inline void lock() {};
+ inline void unlock() {};
+#endif
+
+ private:
+ void output(MprLogModule *module, int flags, int level,
+ char *msg);
+ void breakpoint(char *file, int line);
+};
+
+extern void mprLog(int level, MprLogModule *module, char *fmt, ...);
+extern void mprLog(int level, int flags, MprLogModule *module,
+ char *fmt, ...);
+extern void mprLog(char *fmt, ...);
+
+#else // !BLD_FEATURE_LOG
+//
+// If logging is not enabled, we inline these functions to nothing
+//
+class MprLogModule {
+ void *x;
+ public:
+ MprLogModule(char *name) {}
+};
+inline void mprLog(int level, MprLogModule *module, char *fmt, ...) {};
+inline void mprLog(char *fmt, ...) {}
+extern "C" void mprLog(int level, char *fmt, ...);
+#endif
+
+///////////////////////////////// MprLogModule /////////////////////////////////
+#if BLD_FEATURE_LOG
+//
+// Class to describe a trace log module
+//
+
+class MprLogModule : public MprLink {
+ private:
+ MprStr name;
+ int level; // Current trace output level
+ bool enabled;
+
+ public:
+ MprLogModule(char *name);
+ ~MprLogModule();
+ void innerMprLogModule(char *name);
+ int getLevel(void) { return level; };
+ void disable() { enabled = 0; };
+ void enable() { enabled = 1; };
+ int getEnabled() { return enabled; };
+ char *getName() { return name; };
+ void setLevel(int l) { level = l; };
+};
+
+#endif // BLD_FEATURE_LOG
+//////////////////////////////////// MprBuf ////////////////////////////////////
+
+typedef int (*MprBufProc)(MprBuf* bp, void *arg);
+
+class MprBuf {
+ private:
+ uchar *buf; // Actual buffer for data
+ uchar *endbuf; // Pointer one past the end of buffer
+ uchar *start; // Pointer to next data char
+ uchar *end; // Pointer one past the last data char
+ int buflen; // Current size of buffer
+ int maxsize; // Max size the buffer can ever grow
+ int growBy; // Next growth increment to use
+ MprBufProc refillProc; // Function to refill the buffer
+ void *refillArg; // Arg to refill proc
+
+ public:
+ MprBuf();
+ MprBuf(int initialSize, int maxsize = -1);
+ ~MprBuf();
+ inline void addNull() {
+ *((char*) end) = (char) '\0';
+ };
+ void adjustStart(int size);
+ void adjustEnd(int size);
+ void copyDown();
+ inline void flush() {
+ start = buf;
+ end = buf;
+ };
+ inline int get() {
+ if (start == end) {
+ return -1;
+ }
+ int c = (uchar) *start++;
+ if (start >= endbuf) {
+ start = buf;
+ }
+ return c;
+ };
+ int get(uchar *buf, int len);
+ inline char *getBuf() { return (char*) buf; };
+ inline char *getEnd() { return (char*) end; };
+ inline char *getEndBuf() { return (char*) endbuf; };
+ inline int getLength() {
+ return ((start > end) ?
+ (buflen + (end - start)) : (end - start));
+ };
+ inline int getLinearData() {
+ return min((endbuf - start), getLength());
+ }
+ inline int getLinearSpace() {
+ int len = getLength();
+ int space = buflen - len - 1;
+ return min((endbuf - end), space);
+ }
+ inline int getSpace() {
+ return buflen - getLength() - 1;
+ };
+ inline char *getStart() { return (char*) start; };
+ inline int getSize() { return buflen; };
+ int insert(char c);
+ inline int look() {
+ if (start == end) {
+ return -1;
+ }
+ return* start;
+ }
+ int lookLast();
+ int put(char c);
+ int put(char *str);
+ int putInt(int i);
+ int putFmt(char *fmt, ...);
+ int put(uchar *buf, int len);
+ inline int refill() {
+ return (refillProc) ?
+ (refillProc)(this, refillArg) : 0;
+ };
+ inline void resetIfEmpty() {
+ if (getLength() == 0) {
+ flush();
+ }
+ };
+ void setBuf(uchar *userBuf, int size);
+ void setBuf(int initialSize, int maxSize);
+ void setRefillProc(MprBufProc fn, void *arg) {
+ refillProc = fn;
+ refillArg = arg;
+ };
+ uchar *takeBuffer();
+ private:
+ int grow();
+};
+
+//////////////////////////////// MprCmdService /////////////////////////////////
+#if BLD_FEATURE_CGI_MODULE
+//
+// Flags for MprCmd
+//
+#define MPR_CMD_BACKGROUND 0x1 // Continue running if MPR exits
+#define MPR_CMD_REAP_MAX 24
+
+//
+// Cmd service control
+//
+
+class MprCmdService {
+ private:
+ MprList cmdList; // List of commands
+ MprMutex *mutex; // Multi-thread sync
+ ulong completedCmds[MPR_CMD_REAP_MAX];
+ int exitStatus[MPR_CMD_REAP_MAX];
+ MprTimer *timer; // Timer to poll for child completion
+
+ public:
+ MprCmdService();
+ ~MprCmdService();
+ void cmdWatcher();
+ void cmdWatcherTimer(MprTimer *tp);
+ void insertCmd(MprCmd* rp);
+ void removeCmd(MprCmd* rp);
+ int start();
+ void startWatcher();
+ int stop();
+
+#if LINUX || SOLARIS || VXWORKS
+ void processStatus(int pid, int status);
+ void initSignals();
+#endif
+
+#if BLD_FEATURE_MULTITHREAD
+ void lock() { mutex->lock(); };
+ void unlock() { mutex->unlock(); };
+#else
+ inline void lock() {};
+ inline void unlock() {};
+#endif
+};
+
+//////////////////////////////////// MprCmd ////////////////////////////////////
+
+//
+// Cmd procs must return the number of bytes read or -1 for errors.
+//
+typedef void (*MprCmdProc)(MprCmd* rp, void *data);
+
+#define MPR_CMD_EOF -1 // EOF return value
+
+//
+// Flags
+//
+#define MPR_CMD_DETACHED 0x1
+#define MPR_CMD_NEW_SESSION 0x2
+#define MPR_CMD_CHDIR 0x4
+#define MPR_CMD_WAIT 0x8
+#define MPR_CMD_SHOW 0x10
+#define MPR_CMD_USER_FLAGS 0x1f
+
+#define MPR_CMD_COMPLETE 0x40
+#define MPR_CMD_DISPOSED 0x80
+#define MPR_CMD_STDIO_MADE 0x100
+
+//
+// Indicies for clientFd and serverFd
+//
+#define MPR_CMD_IN 0 // Stdin for the server
+#define MPR_CMD_OUT 1 // Stdout for the server
+#define MPR_CMD_MAX_FD 2
+
+#define MPR_CMD_WATCHER_NAP 100 // Timeout for watcher while polling
+#define MPR_CMD_WATCHER_TIMEOUT 5000 // Timeout for child to start
+
+class MprCmdFiles {
+ public:
+ MprStr name[MPR_CMD_MAX_FD];
+ int fd[MPR_CMD_MAX_FD];
+ int clientFd[MPR_CMD_MAX_FD];
+ public:
+ MprCmdFiles();
+ ~MprCmdFiles();
+};
+
+//
+// MprCmd class
+//
+class MprCmd : public MprLink {
+ private:
+ MprStr cwd; // Current working dir for the process
+ void *data; // Callback user data
+ int exitStatus; // Command exit status
+ int flags; // Control flags (userFlags not here)
+ MprCmdFiles files; // Stdin, stdout for the command
+ int inUse; // Used by dispose()
+ MprLogModule *log;
+ MprCmdProc cmdDoneProc; // Handler for client completion
+
+#if VXWORKS
+ MprSelectHandler
+ *handler;
+ int waitFd; // Pipe to await child exit
+#endif
+ ulong process; // Id/handle of the created process
+
+#if BLD_FEATURE_MULTITHREAD
+#if VXWORKS
+ MprCond *startCond;
+ MprCond *exitCond;
+#endif
+ MprMutex *mutex;
+#endif
+
+ public:
+ MprCmd();
+ ~MprCmd();
+ void closeWriteFd();
+ int dispose();
+ int getExitCode(int *code = 0);
+ int getWriteFd();
+ int getReadFd();
+ void invokeCallback(MprMutex *callerMutex);
+ bool isRunning();
+ int makeStdio();
+ void setCwd(char *dir);
+ int setInuse();
+ int start(char *cmd, int flags);
+ int start(char *cmd, char **argv, char **envp,
+ MprCmdProc completionProc, void *data, int flags);
+ void stop();
+
+ //
+ // Internal API
+ //
+ ulong getProcess() { return process; };
+ void reset();
+ void resetFiles();
+ void setExitStatus(int status);
+
+ private:
+ int waitForChild(int timeout);
+
+#if BLD_FEATURE_MULTITHREAD
+ void lock() { mutex->lock(); };
+ void unlock() { mutex->unlock(); };
+#else
+ inline void lock() {};
+ inline void unlock() {};
+#endif
+
+ friend class MprCmdService;
+};
+
+#endif // BLD_FEATURE_CGI_MODULE
+////////////////////////////// MprSelectService ////////////////////////////////
+//
+// Standard select bit mask options
+//
+#define MPR_READABLE 0x2
+#define MPR_WRITEABLE 0x4
+#define MPR_EXCEPTION 0x8
+
+typedef void (*MprSelectProc)(void *data, int mask, int isMprPoolThread);
+
+class MprSelectService {
+ private:
+ struct sockaddr_in
+ breakAddress; // Breakout port socket address
+ int breakSock; // MprSocket to wakeup select service
+ int breakPort; // Port to talk to the select service
+ int breakRetries; // Retry attempts to open breakout port
+ MprList list; // List of select handlers
+ int flags; // State flags
+ int maskGeneration; // Generation number for mask changes
+ int listGeneration; // Generation number for list changes
+ MprLogModule *log;
+ int rebuildMasks; // Complete select mask rebuild required
+ int delayedFds[FD_SETSIZE];
+ int maxDelayedFd;
+#if WIN
+ int sockMessage; // MprSocket message for AsyncSelect
+ HWND hwnd; // Window handle to use for AsyncSelect
+#endif
+
+#if BLD_FEATURE_MULTITHREAD
+ MprCond *cond; // Wait for select to breakout
+ MprMutex *mutex; // General multi-thread synchronization
+#endif
+
+ public:
+ //
+ // Published API
+ //
+ MprSelectService();
+ ~MprSelectService();
+ int getFds(fd_set *readInterest, fd_set *writeInterest,
+ fd_set *exceptInterest, int *maxFd, int *lastGet);
+ void serviceIO(int readyFds, fd_set *readFds, fd_set *writeFds,
+ fd_set *exceptFds);
+ void serviceIO(int sockFd, int winMask);
+
+ //
+ // Unpublished API
+ //
+ int insertHandler(MprSelectHandler *sp);
+ void awaken(int wait = 0);
+ void delayedClose(int fd);
+ bool getAsyncSelectMode();
+ int getFlags() { return flags; };
+ int modifyHandler(MprSelectHandler *sp, bool wakeUp);
+ void removeHandler(MprSelectHandler *sp);
+ MprLogModule *getLog() { return log; };
+ int openBreakoutPort();
+ void setPort(int n);
+ int start();
+ int stop();
+
+#if BLD_FEATURE_MULTITHREAD
+ void lock() { mutex->lock(); };
+ void unlock() { mutex->unlock(); };
+#else
+ inline void lock() {};
+ inline void unlock() {};
+#endif
+
+#if WIN
+ HWND getHwnd() { return hwnd; };
+ int getMessage() { return sockMessage; };
+ void setHwnd(HWND h) { hwnd = (HWND) h; };
+ void setMessage(int m) { sockMessage = m; };
+ void setAsyncSelectMode(bool asyncSelect);
+#endif
+};
+
+////////////////////////////// MprSelectHandler ////////////////////////////////
+//
+// Flags
+//
+#define MPR_SELECT_DISPOSED 0x1
+#define MPR_SELECT_RUNNING 0x2
+#define MPR_SELECT_CLOSEFD 0x4
+#define MPR_SELECT_CLIENT_CLOSED 0x8 // Client disconnection received
+
+class MprSelectHandler : public MprLink {
+ private:
+ int desiredMask; // Mask of desired events
+ int disableMask; // Mask of disabled events
+ int fd; // O/S File descriptor (sp->sock)
+ int flags; // Control flags
+ void *handlerData; // Argument to pass to proc.
+ int inUse; // Used by dispose()
+ MprLogModule *log;
+ int presentMask; // Mask of events that have been seen
+ int priority; // Priority if events handled by threads
+
+#if BLD_FEATURE_MULTITHREAD
+ MprCond *stoppingCond; // Synchronization when stopping
+#endif
+
+ public:
+ MprSelectService *selectService; // Select service pointer
+ MprSelectProc proc; // Select handler procedure
+
+ public:
+ MprSelectHandler(int fd, int mask, MprSelectProc proc,
+ void *data, int priority);
+ bool dispose();
+ void disableEvents(bool wakeUp);
+ void enableEvents(bool wakeUp);
+ int getFd() { return fd; };
+ int getFlags() { return flags; };
+ void runHandler();
+ void selectProc(MprTask *tp);
+ void setInterest(int mask);
+ void setWinInterest();
+ void setProc(MprSelectProc newProc, int mask);
+ void setCloseOnDispose();
+ int stop(int timeout);
+
+ private:
+ ~MprSelectHandler();
+
+ friend class MprSelectService;
+};
+
+//////////////////////////////// MprInterface //////////////////////////////////
+
+class MprInterface : public MprLink {
+ public:
+ MprStr name; // Interface name
+ MprStr ipAddr;
+ MprStr broadcast;
+ MprStr mask;
+ public:
+ MprInterface(char *name, char *ipAddr, char *bcast,
+ char *mask);
+ ~MprInterface();
+};
+
+////////////////////////////// MprSocketService ////////////////////////////////
+
+typedef void (*MprSocketIoProc)(void *data, MprSocket *sp, int mask,
+ int isMprPoolThread);
+typedef void (*MprSocketAcceptProc)(void *data, MprSocket *sp, char *ip,
+ int port, MprSocket *lp, int isMprPoolThread);
+//
+// Mpr socket service class
+//
+class MprSocketService {
+ private:
+ MprList socketList; // List of all sockets
+ MprList ipList; // List of ip addresses
+ MprLogModule *log;
+
+#if BLD_FEATURE_MULTITHREAD
+ MprMutex *mutex;
+#endif
+
+ public:
+ MprSocketService();
+ ~MprSocketService();
+#if BLD_FEATURE_LOG
+ MprLogModule *getLogModule() { return log; };
+#endif
+ MprList *getInterfaceList();
+ void insertMprSocket(MprSocket *sp);
+ void removeMprSocket(MprSocket *sp);
+ int start();
+ int stop();
+
+#if BLD_FEATURE_MULTITHREAD
+ void lock() { mutex->lock(); };
+ void unlock() { mutex->unlock(); };
+#else
+ inline void lock() {};
+ inline void unlock() {};
+#endif
+
+ private:
+ int getInterfaces();
+};
+
+////////////////////////////////// MprSocket ///////////////////////////////////
+//
+// close flags
+//
+#define MPR_SHUTDOWN_READ 0
+#define MPR_SHUTDOWN_WRITE 1
+#define MPR_SHUTDOWN_BOTH 2
+
+//
+// Flags
+//
+#define MPR_SOCKET_BLOCK 0x1 // Use blocking I/O
+#define MPR_SOCKET_BROADCAST 0x2 // Broadcast mode
+#define MPR_SOCKET_CLOSED 0x4 // MprSocket has been closed
+#define MPR_SOCKET_CONNECTING 0x8 // MprSocket has been closed
+#define MPR_SOCKET_DATAGRAM 0x10 // Use datagrams
+#define MPR_SOCKET_EOF 0x20 // Seen end of file
+#define MPR_SOCKET_LISTENER 0x40 // MprSocket is server listener
+#define MPR_SOCKET_NOREUSE 0x80 // Dont set SO_REUSEADDR option
+#define MPR_SOCKET_NODELAY 0x100 // Disable Nagle algorithm
+#define MPR_SOCKET_DISPOSED 0x200 // Delete requested
+
+#define MPR_SOCKET_READABLE 0x2
+#define MPR_SOCKET_WRITABLE 0x4
+#define MPR_SOCKET_EXCEPTION 0x8
+
+class MprSocket : public MprLink
+{
+ private:
+ MprSocketAcceptProc
+ acceptCallback; // Accept callback
+ void *acceptData; // User accept callback data
+ int currentEvents; // Mask of ready events (FD_x)
+ int error; // Last error
+ MprSelectHandler *handler; // Select handler
+ int handlerMask; // Handler events of interest
+ int handlerPriority; // Handler priority
+ int interestEvents; // Mask of events to watch for
+ MprSocketIoProc ioCallback; // User I/O callback
+ void *ioData; // User io callback data
+ void *ioData2; // Secondary user io callback data
+ int inUse; // In use counter. Used by dispose()
+ MprStr ipAddr; // Host IP address
+ MprLogModule *log; // Pointer to MprSocketService module
+ int port; // Port to listen on
+ int selectEvents; // Events being selected
+
+#if BLD_FEATURE_MULTITHREAD
+ MprMutex *mutex; // Multi-thread sync
+#endif
+
+ protected:
+ int sock; // Actual socket handle
+ int flags; // Current state flags
+ bool secure; // MprSocket is using SSL
+
+ public:
+ MprSocket();
+ void forcedClose();
+ void acceptProc(int isMprPoolThread);
+ bool getEof();
+ int getError();
+ int getFlags();
+ char *getIpAddr() { return ipAddr; };
+ int getPort();
+ int getFd();
+ bool getBlockingMode();
+ void getAcceptCallback(MprSocketAcceptProc *fn, void **data);
+ void getCallback(MprSocketIoProc *fn, void **data,
+ void **data2, int *mask);
+ bool isSecure() { return secure; };
+ int openServer(char *ipAddr, int portNum,
+ MprSocketAcceptProc acceptFn, void *data, int flags);
+ int openClient(char *hostName, int portNum, int flags);
+ void setBlockingMode(bool on);
+ int setBufSize(int sendSize, int recvSize);
+ // FUTURE -- rename: handler vs callback
+ void setCallback(MprSocketIoProc fn, void *data,
+ void *data2, int mask, int pri = MPR_NORMAL_PRIORITY);
+ int write(char *s);
+
+ virtual ~MprSocket();
+ virtual void close(int how);
+ virtual bool dispose();
+ virtual void ioProc(int mask, int isMprPoolThread);
+ virtual MprSocket
+ *newSocket();
+ virtual int read(char *buf, int len);
+ virtual int write(char *buf, int len);
+
+#if BLD_FEATURE_MULTITHREAD
+ void lock() { mutex->lock(); };
+ void unlock() { mutex->unlock(); };
+#else
+ inline void lock() {};
+ inline void unlock() {};
+#endif
+
+ private:
+ void setMask(int handlerMask);
+ void setNoDelay(bool on);
+
+ friend class MprSocketService;
+};
+
+//////////////////////////////// MprPoolService ////////////////////////////////
+
+#if BLD_DEBUG
+class MprPoolStats {
+ public:
+ int maxThreads; // Configured max number of threads
+ int minThreads; // Configured minimum
+ int numThreads; // Configured minimum
+ int maxUse; // Max used
+ int pruneHighWater; // Peak thread use in last minute
+ int idleThreads; // Current idle
+ int busyThreads; // Current busy
+};
+#endif
+
+//
+// A task queue consists of a list of tasks and optional list of threads
+//
+typedef void (*MprTaskProc)(void *data, MprTask *tp);
+
+//
+// Class for the overall thread pool service
+//
+class MprPoolService {
+ protected: // Allow MprPoolThreads to access
+ MprStr name; // Name of pool
+ int nextTaskNum; // Unique next task number
+ MprList runningTasks; // List of executing tasks
+ int stackSize; // Stack size for worker threads
+ MprList tasks; // Prioritized list of pending tasks
+
+#if BLD_FEATURE_MULTITHREAD
+ MprList busyThreads; // List of threads to service tasks
+ MprList idleThreads; // List of threads to service tasks
+ int maxThreads; // Max # threads in pool
+ int maxUseThreads; // Max threads ever used
+ int minThreads; // Max # threads in pool
+ MprMutex *mutex; // Per task synchronization
+ int nextThreadNum; // Unique next thread number
+ int numThreads; // Current number of threads in pool
+ int pruneHighWater; // Peak thread use in last minute
+ MprTimer *pruneTimer; // Timer for excess threads pruner
+ MprMutex *incMutex; // Per task synchronization
+#endif
+
+ public:
+ MprLogModule *log;
+
+ public:
+ MprPoolService(char *name);
+ ~MprPoolService();
+ int assignNextTask(MprPoolThread *pt);
+ void dequeueTask(MprTask *tp);
+#if BLD_DEBUG
+ void getStats(MprPoolStats *ps);
+#endif
+ void insertTask(MprTask *np, MprTask *tp);
+ void prune();
+ void queueTask(MprTask *tp);
+ void queueRunningTask(MprTask *tp);
+ void removeTask(MprTask *tp);
+ int runTasks();
+ void setStackSize(int n);
+ int start();
+ int stop(int timeout);
+
+#if BLD_FEATURE_MULTITHREAD
+ void dispatchTasks();
+ int getMinPoolThreads() { return minThreads; };
+ int getNumPoolThreads() {
+ return idleThreads.getNumItems() +
+ busyThreads.getNumItems();
+ };
+ int getMaxPoolThreads() { return maxThreads; };
+ int getNumIdleThreads() { return idleThreads.getNumItems(); };
+ void lock();
+ int getNextThreadNum();
+ void removeThread(MprPoolThread *pt);
+ void setMinPoolThreads(int n);
+ void setMaxPoolThreads(int n);
+ void unlock();
+#else
+ inline void lock() {};
+ inline void unlock() {};
+ int getMaxPoolThreads() { return 0; };
+#endif
+
+ friend class MprPoolThread;
+ friend class MprTask;
+};
+
+///////////////////////////////// MprPoolThread ////////////////////////////////
+#if BLD_FEATURE_MULTITHREAD
+//
+// Flags
+//
+#define MPR_POOL_THREAD_SLEEPING 0x1
+
+//
+// Class for each thread in the thread pool
+//
+class MprPoolThread : public MprLink {
+ private:
+ MprPoolService *pool; // Which thread pool do we swim in
+ MprTask *currentTask; // Current task being run
+ int flags;
+
+#if BLD_FEATURE_MULTITHREAD
+ MprThread *thread; // Associated thread
+ MprCond *idleCond; // Used to wait for work
+#endif
+
+ public:
+ MprPoolThread(MprPoolService *pool, int stackSize);
+ ~MprPoolThread();
+ MprPoolService *getMprPoolService() { return pool; };
+ MprThread *getThread() { return thread; };
+ MprTask *getCurrentTask() { return currentTask; };
+ void makeIdle();
+ void start();
+ void setTask(MprTask *tp);
+ void threadMain();
+ void wakeup();
+};
+
+#endif
+/////////////////////////////////// MprTask ////////////////////////////////////
+//
+// Flags
+//
+#define MPR_TASK_DISPOSED 0x1
+#define MPR_TASK_RUNNING 0x2
+
+//
+// Class for each task (unit of work)
+//
+class MprTask : public MprLink {
+ public:
+ void *data; // Task data
+ int flags; // Control flags
+ int inUse; // In use counter. Used by dispose()
+ MprPoolService *pool; // Managing pool
+ int priority; // Priority of event
+ MprTaskProc proc; // Procedure to service this event.
+
+#if BLD_FEATURE_MULTITHREAD
+ MprPoolThread *pt; // Pool thread servicing this task
+ MprCond *stoppingCond; // Synchronization for timer->dispose()
+#endif
+
+ public:
+ MprTask(MprTaskProc proc, void *data,
+ int priority = MPR_NORMAL_PRIORITY);
+ MprTask(MprPoolService *pool, MprTaskProc proc,
+ void *data, int priority = MPR_NORMAL_PRIORITY);
+ bool dispose();
+ void start();
+ int stop(int timeout);
+
+#if BLD_FEATURE_MULTITHREAD
+ MprPoolThread *getThread() { return pt; };
+#endif
+
+ private:
+ ~MprTask();
+ friend class MprPoolThread;
+ friend class MprPoolService;
+};
+
+/////////////////////////////// MprThreadService ///////////////////////////////
+#if BLD_FEATURE_MULTITHREAD
+//
+// Threading primitives
+//
+typedef void (*MprThreadProc)(void *arg, MprThread *tp);
+
+class MprThreadService {
+ private:
+ MprList threads; // List of all threads
+ MprThread *mainThread; // Main application Mpr thread id
+ MprMutex *mutex; // Multi-thread sync
+
+ public:
+ MprThreadService();
+ ~MprThreadService();
+ MprThread *getCurrentThread();
+ void insertThread(MprThread *tp);
+ void removeThread(MprThread *tp);
+ int start();
+ int stop(int timeout);
+
+ inline void lock() {
+ if (mutex) {
+ mutex->lock();
+ }
+ };
+ inline void unlock() {
+ if (mutex) {
+ mutex->unlock();
+ }
+ };
+};
+
+/////////////////////////////////// MprThread //////////////////////////////////
+
+class MprThread : public MprLink {
+ private:
+ #if WIN
+ int osThreadId; // O/S thread id
+ handle threadHandle; // Threads OS handle
+ #endif
+ #if LINUX || MACOSX || SOLARIS
+ pthread_t osThreadId; // O/S thread id
+ #endif
+ #if VXWORKS
+ int osThreadId; // O/S thread id (same as pid)
+ #endif
+ void *data; // Data argument
+ MprThreadProc entry; // Users thread entry point
+ MprStr name; // Name of thead for trace
+ MprMutex *mutex; // Multi-thread synchronization
+ int pid; // Owning process id
+ int priority; // Current priority
+ int stackSize; // Only VxWorks implements
+
+ public:
+ MprThread(int pri, char *name);
+ // FUTURE -- move pri to last and default it.
+ MprThread(MprThreadProc proc, int pri, void *data,
+ char *name, int stackSize = 0);
+ ~MprThread();
+ int getId() { return (int) osThreadId; };
+ char *getName() { return name; };
+ int getPriority() { return priority; };
+ void lock() { mutex->lock(); };
+ void setId(int id);
+ void setPriority(int priority);
+ void setStackSize(int size);
+ int start();
+ void threadProc();
+ void unlock() { mutex->unlock(); };
+
+ private:
+ int mapMprPriorityToOs(int mprPriority);
+ int mapOsPriorityToMpr(int nativePriority);
+};
+
+extern MprThread *mprGetCurrentThread();
+extern int mprGetMaxPoolThreads();
+
+#endif // BLD_FEATURE_MULTITHREAD
+/////////////////////////////// MprTimerService ////////////////////////////////
+
+#define MPR_TIMER_TOLERANCE 2 // Used in timer calculations
+
+//
+// Timer service. One per MPR
+//
+class MprTimerService {
+ private:
+ int lastIdleTime; // Last return value from getIdleTime()
+ int lastRanTimers; // Last call to runTimers()
+ MprLogModule *log; // Log module to identify trace
+ MprList timerList; // List of all timers
+
+#if BLD_FEATURE_MULTITHREAD
+ MprMutex *mutex; // Multi-thread sync
+#endif
+
+ public:
+ MprTimerService();
+ ~MprTimerService();
+ void callTimer(MprTimer *tp);
+ int getIdleTime();
+ int runTimers();
+ int stop();
+ int start();
+
+#if BLD_FEATURE_MULTITHREAD
+ MprMutex *getMutex() { return mutex; };
+ inline void lock() { mutex->lock(); };
+ inline void unlock() { mutex->unlock(); };
+#else
+ inline void lock() {};
+ inline void unlock() {};
+#endif
+
+ protected:
+ void updateSelect(MprTimer *tp);
+
+ friend class MprTimer;
+};
+
+//////////////////////////////////// MprTimer //////////////////////////////////
+//
+// MprTimer callback function prototype
+//
+typedef void (*MprTimerProc)(void *data, MprTimer *tp);
+
+//
+// MprTimer flags
+//
+#define MPR_TIMER_DISPOSED 0x1
+#define MPR_TIMER_RUNNING 0x2
+#define MPR_TIMER_TASK 0x4
+#define MPR_TIMER_AUTO_RESCHED 0x8
+
+class MprTimer : public MprLink {
+ private:
+ void *data; // Argument to pass to callback
+ int flags;
+ int inUse; // In use counter. Used by dispose()
+ int period; // Reschedule period
+ MprTimerProc proc; // Callback procedure
+ MprTime time; // When timer is due to next run
+ MprTimerService *timerService;
+
+#if BLD_FEATURE_MULTITHREAD
+ MprCond *stoppingCond; // Synchronization when stopping
+#endif
+
+ public:
+ MprTimer(int msec, MprTimerProc routine, void *arg,
+ int userFlags = 0);
+ bool dispose();
+ int getPeriod() { return period; };
+ MprTimerService *getMprTimerService() { return timerService; };
+ void reschedule();
+ void reschedule(int msec);
+ int stop(int timeout);
+
+private:
+ ~MprTimer();
+ friend class MprTimerService;
+};
+
+//////////////////////////////// MprWinService /////////////////////////////////
+#if BLD_FEATURE_RUN_AS_SERVICE && WIN
+
+class MprWinService {
+ private:
+ MprStr svcName;
+ public:
+ MprWinService(char *name);
+ ~MprWinService();
+ int install(char *displayName, char *cmd);
+ int registerService(HANDLE threadHandle, HANDLE waitEvent);
+ int remove(int code);
+ int startDispatcher(LPSERVICE_MAIN_FUNCTION svcMain);
+ int start();
+ int stop(int code);
+ void updateStatus(int status, int exitCode);
+};
+
+#endif
+////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////// Other C++ Stuff ////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+#if BLD_DEBUG && UNUSED
+#if LINUX || MACOSX
+#if MPR_CPU_IX86
+ inline int64 mprGetHiResTime() {
+ int64 now;
+ __asm__ __volatile__ ("rdtsc" : "=A" (now));
+ return now;
+ }
+#endif
+#endif
+#if WIN
+ inline int64 mprGetHiResTime() {
+ int64 now;
+ QueryPerformanceCounter((LARGE_INTEGER*) &now);
+ return now;
+ }
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+
+inline int64 mprGetElapsedTime()
+{
+ static int64 lastMark = 0;
+ int64 now, elapsed;
+
+ now = mprGetHiResTime();
+ if (now > lastMark) {
+ elapsed = now - lastMark;
+ lastMark = now;
+ } else {
+ elapsed = lastMark - now + 1;
+ lastMark = now;
+ }
+ return elapsed;
+};
+
+#endif // BLD_DEBUG && UNUSED
+#endif // __cplusplus
+
+////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////// C Prototypes //////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Generic array type
+ */
+typedef struct MprArray {
+ int max; /**< Size of the handles array. */
+ int used; /**< Count of used entries in handles. */
+ void **handles;
+} MprArray;
+
+#if BLD_FEATURE_SQUEEZE
+#define MPR_ARRAY_INCR 8
+#else
+#define MPR_ARRAY_INCR 16
+#endif
+
+//
+// Array
+//
+extern MprArray *mprCreateArray();
+extern void mprDestroyArray(MprArray *array);
+extern int mprAddToArray(MprArray *array, void *item);
+extern int mprRemoveFromArray(MprArray *array, int index);
+
+//
+// Printf replacements
+//
+#define MPR_STDOUT 1
+#define MPR_STDERR 2
+
+extern int mprPrintf(char *fmt, ...);
+extern int mprStaticPrintf(char *fmt, ...);
+extern int mprFprintf(int fd, char *fmt, ...);
+extern int mprAllocSprintf(char **s, int n, char *fmt, ...);
+extern int mprAllocVsprintf(char **s, int n, char *fmt, va_list arg);
+extern int mprSprintf(char *s, int n, char *fmt, ...);
+extern int mprVsprintf(char *s, int n, char *fmt, va_list arg);
+extern char *mprItoa(int value, char *userBuf, int width);
+extern int mprAtoi(char *str, int radix);
+
+//
+// Safe string routines
+//
+extern int mprStrcpy(char *dest, int destMax, const char *src);
+extern int mprMemcpy(char *dest, int destMax, const char *src,
+ int nbytes);
+extern int mprAllocStrcpy(char **dest, int max, const char *src);
+extern int mprReallocStrcpy(char **dest, int max, const char *src);
+extern int mprAllocMemcpy(char **dest, int destMax, const char *src,
+ int nbytes);
+extern int mprStrcat(char *dest, int max, const char *delim,
+ const char *src, ...);
+extern int mprAllocStrcat(char **dest, int max, const char *delim,
+ const char *src, ...);
+extern int mprReallocStrcat(char **dest, int max, int existingLen,
+ const char *delim, const char *src, ...);
+extern int mprStrlen(char *src, int max);
+
+// FUTURE (rename to Strcmpi, Strncmpi)
+extern int mprStrCmpAnyCase(char *s1, char *s2);
+extern int mprStrCmpAnyCaseCount(char *s1, char *s2, int len);
+extern char *mprStrLower(char *string);
+extern char *mprStrUpper(char *string);
+extern char *mprStrTrim(char *string, char c);
+
+//
+// Reentrant string and time routines
+//
+extern char *mprStrTok(char *str, const char *sep, char **last);
+extern char *mprGetWordTok(char *word, int wordLen, char *str,
+ const char *delim, char **tok);
+extern int mprCtime(const time_t* timer, char *buf, int bufsize);
+extern int mprGetTime(MprTime *tp);
+extern int mprAsctime(const struct tm *timeptr, char *buf, int bufsiz);
+extern struct tm *mprGmtime(time_t* now, struct tm *tmp);
+extern struct tm *mprLocaltime(time_t* now, struct tm *tmp);
+extern int mprRfcTime(char *buf, int size, const struct tm *timeptr);
+
+//
+// General other xPlatform routines
+//
+extern char *mprGetBaseName(char *name);
+extern int mprGetDirName(char *buf, int bufsize, char *path);
+extern void mprMakeArgv(char *prog, char *cmd, char ***argv, int *argc);
+extern int mprMakeDir(char *path);
+extern char *mprInetNtoa(char *buf, int size, const struct in_addr in);
+extern void mprSleep(int msec);
+extern struct hostent* mprGetHostByName(char *name);
+extern void mprFreeGetHostByName(struct hostent* hostp);
+extern int mprGetRandomBytes(uchar *buf, int size, int block);
+
+#if BLD_FEATURE_MULTITHREAD
+extern char *mprGetCurrentThreadName();
+extern void mprLock();
+extern void mprUnlock();
+#else
+#if __cplusplus
+inline void mprLock() {};
+inline void mprUnlock() {};
+#else
+#define mprLock()
+#define mprUnlock()
+#endif
+#endif
+
+extern bool mprGetDebugMode();
+extern void mprSetDebugMode(bool on);
+
+extern int mprGetOsError();
+extern char *mprGetErrorMsg(int errCode);
+extern char *mprMakeTempFileName(char *buf, int bufsize, char *tempDir);
+extern void mprNextFds(char *msg);
+extern char *mprGetFullPathName(char *buf, int buflen, char *path);
+
+extern void mprError(char *file, int line, int flags, char *fmt, ...);
+
+
+#if BLD_FEATURE_LOG || !__cplusplus
+extern void mprLog(int level, char *fmt, ...);
+#endif
+
+typedef void (*MprMemProc)(int askSize, int totalPoolMem, int limit);
+
+extern void *mprCalloc(uint numElem, uint size);
+extern int mprCreateMemHeap(char *userBuf, int initialSize, int limit);
+extern void mprFree(void *ptr);
+extern void *mprMalloc(uint size);
+extern void mprMemClose();
+#if BLD_FEATURE_MALLOC_HOOK
+extern void mprHookMalloc();
+#endif
+extern void mprMemStop();
+extern void mprPrintMemStats();
+extern void *mprRealloc(void *ptr, uint size);
+extern void mprRequestMemStats(bool on);
+extern void mprSetMemHandler(MprMemProc cback);
+extern char *mprStrdup(const char *str);
+
+#if WIN
+extern int mprReadRegistry(char *key, char *val, char **buf, int max);
+#endif
+
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+#endif // _h_MPR
+
+//
+// Local variables:
+// tab-width: 4
+// c-basic-offset: 4
+// End:
+// vim:tw=78
+// vim600: sw=4 ts=4 fdm=marker
+// vim<600: sw=4 ts=4
+//