/// /// @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 //