/* mpr.h -- Header for the Multithreaded Portable Runtime (MPR). Copyright (c) All Rights Reserved. See details at the end of the file. */ /** @file mpr.h The Multithreaded Portable Runtime (MPR) is a portable runtime library for embedded applications. @description The MPR provides management for logging, error handling, events, files, http, memory, ssl, sockets, strings, xml parsing, and date/time functions. It also provides a foundation of safe routines for secure programming, that help to prevent buffer overflows and other security threats. The MPR is a library and a C API that can be used in both C and C++ programs. \n\n The MPR uses a set extended typedefs for common types. These include: bool, cchar, cvoid, uchar, short, ushort, int, uint, long, ulong, int32, uint32, int64, uint64, float, and double. The cchar type is a const char, cvoid is const void. Several types have "u" prefixes to denote unsigned qualifiers. \n\n The MPR includes a memory allocator and generational garbage collector. The allocator is a fast, immediate coalescing allocator that will return memory back to the O/S if not required. It is optimized for frequent allocations of small blocks (< 4K) and uses a scheme of free queues for fast allocation. \n\n The MPR provides a high-performance thread-pool to share threads as required to service clients. When a client request arrives, the MPR allocates an event queue called a dispatcher. This dispatcher then serializes all activity for the request so that it essentially runs single-threaded This simplifies the code as most interactions do not need to be lock protected. When a request has activity, it borrows a thread from the thread pool, does its work and then returns the thread to the thread pool. This all happens very quickly, so a small pool of threads are effectivelyshared over many requests. Thread are free to block if required, but typically non-blocking patterns are more economical. If you have non-MPR threads that need to call into the MPR, you must synchronize such calls via #mprCreateEvent. */ #ifndef _h_MPR #define _h_MPR 1 /********************************** Includes **********************************/ #include "me.h" #include "osdep.h" /*********************************** Defines **********************************/ #if DOXYGEN /** Argument for sockets */ typedef int Socket; /** Unsigned integral type. Equivalent in size to void* */ typedef long size_t; #endif #ifdef __cplusplus extern "C" { #endif struct tm; struct Mpr; struct MprMem; struct MprBuf; struct MprCmd; struct MprCache; struct MprCond; struct MprDispatcher; struct MprEvent; struct MprEventService; struct MprFile; struct MprFileSystem; struct MprHash; struct MprHeap; struct MprJson; struct MprJsonParser; struct MprList; struct MprKey; struct MprModule; struct MprMutex; struct MprOsService; struct MprPath; struct MprSignal; struct MprSocket; struct MprSocketService; struct MprSsl; struct MprThread; struct MprThreadService; struct MprWaitService; struct MprWaitHandler; struct MprWorker; struct MprWorkerService; struct MprXml; #ifndef ME_MPR_LOGGING #define ME_MPR_LOGGING 1 /**< Default for logging is "on" */ #endif #ifndef ME_MPR_DEBUG_LOGGING #if ME_DEBUG #define ME_MPR_DEBUG_LOGGING 1 #else #define ME_MPR_DEBUG_LOGGING 0 #endif #endif #ifndef ME_MPR_TEST #define ME_MPR_TEST 1 #endif #ifndef ME_MPR_MAX_PASSWORD #define ME_MPR_MAX_PASSWORD 256 /**< Max password length */ #endif #ifndef ME_MPR_THREAD_LIMIT_BY_CORES #define ME_MPR_THREAD_LIMIT_BY_CORES 1 #endif /* Select wakeup port. Port can be any free port number. If this is not free, the MPR will use the next free port. */ #ifndef ME_WAKEUP_ADDR #define ME_WAKEUP_ADDR "127.0.0.1" #endif #ifndef ME_WAKEUP_PORT #define ME_WAKEUP_PORT 9473 #endif #define MPR_FD_MIN 32 /* Signal sent on Unix to break out of a select call. */ #define MPR_WAIT_SIGNAL (SIGUSR2) /* Socket event message */ #define MPR_SOCKET_MESSAGE (WM_USER + 32) /* Coalesce vectored write packets when using SSL */ #ifndef ME_MPR_SOCKET_VECTOR_JOIN #define ME_MPR_SOCKET_VECTOR_JOIN 1 #endif /* Priorities */ #define MPR_BACKGROUND_PRIORITY 15 /**< May only get CPU if idle */ #define MPR_LOW_PRIORITY 25 #define MPR_NORMAL_PRIORITY 50 /**< Normal (default) priority */ #define MPR_HIGH_PRIORITY 75 #define MPR_CRITICAL_PRIORITY 99 /**< May not yield */ #define MPR_EVENT_PRIORITY 50 /**< Normal priority */ #define MPR_WORKER_PRIORITY 50 /**< Normal priority */ #define MPR_REQUEST_PRIORITY 50 /**< Normal priority */ /* Timeouts */ #define MPR_TIMEOUT_PRUNER 120000 /**< Time between worker thread pruner runs (2 min) */ #define MPR_TIMEOUT_WORKER 60000 /**< Prune worker that has been idle for 1 min */ #define MPR_TIMEOUT_START_TASK 10000 /**< Time to start tasks running */ #define MPR_TIMEOUT_STOP 30000 /**< Default wait when stopping resources (30 sec) */ #define MPR_TIMEOUT_STOP_TASK 10000 /**< Time to stop or reap tasks (vxworks) */ #define MPR_TIMEOUT_LINGER 2000 /**< Close socket linger timeout */ #define MPR_TIMEOUT_GC_SYNC 100 /**< Short wait period for threads to synchronize */ #define MPR_TIMEOUT_NO_BUSY 1000 /**< Wait period to minimize CPU drain */ #define MPR_TIMEOUT_NAP 20 /**< Short pause */ #define MPR_MAX_TIMEOUT MAXINT64 /* Default thread counts */ #define MPR_DEFAULT_MIN_THREADS 0 /**< Default min threads */ #define MPR_DEFAULT_MAX_THREADS 5 /**< Default max threads */ /* 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 msec to hold a lock */ #define MPR_TIMER_TOLERANCE 2 /* Used in timer calculations */ #define MPR_CMD_TIMER_PERIOD 5000 /* Check for expired commands */ /** Events */ #define MPR_EVENT_TIME_SLICE 20 /* 20 msec */ /** Maximum number of files to close when forking */ #define MPR_MAX_FILE 256 /* Event notification mechanisms */ #define MPR_EVENT_ASYNC 1 /**< Windows async select */ #define MPR_EVENT_EPOLL 2 /**< epoll_wait */ #define MPR_EVENT_KQUEUE 3 /**< BSD kqueue */ #define MPR_EVENT_SELECT 4 /**< traditional select() */ #define MPR_EVENT_SELECT_PIPE 5 /**< Select with pipe for wakeup */ #ifndef ME_EVENT_NOTIFIER #if MACOSX || SOLARIS #define ME_EVENT_NOTIFIER MPR_EVENT_KQUEUE #elif WINDOWS #define ME_EVENT_NOTIFIER MPR_EVENT_ASYNC #elif VXWORKS #define ME_EVENT_NOTIFIER MPR_EVENT_SELECT #elif LINUX #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) #define ME_EVENT_NOTIFIER MPR_EVENT_EPOLL #else #define ME_EVENT_NOTIFIER MPR_EVENT_SELECT #endif #else #define ME_EVENT_NOTIFIER MPR_EVENT_SELECT #endif #endif /** Maximum number of notifier events */ #ifndef ME_MAX_EVENTS #define ME_MAX_EVENTS 32 #endif /* Garbage collector tuning */ #define MPR_MIN_TIME_FOR_GC 2 /**< Wait till 2 milliseconds of idle time possible */ /************************************ Error Codes *****************************/ /* Prevent collisions with 3rd party software */ #undef UNUSED /* Standard errors */ #define MPR_ERR_OK 0 /**< Success */ #define MPR_ERR_BASE -1 /**< Base error code */ #define MPR_ERR -1 /**< Default error code */ #define MPR_ERR_ABORTED -2 /**< Action aborted */ #define MPR_ERR_ALREADY_EXISTS -3 /**< Item already exists */ #define MPR_ERR_BAD_ARGS -4 /**< Bad arguments or paramaeters */ #define MPR_ERR_BAD_FORMAT -5 /**< Bad input format */ #define MPR_ERR_BAD_HANDLE -6 /**< Bad file handle */ #define MPR_ERR_BAD_STATE -7 /**< Module is in a bad state */ #define MPR_ERR_BAD_SYNTAX -8 /**< Input has bad syntax */ #define MPR_ERR_BAD_TYPE -9 /**< Bad object type */ #define MPR_ERR_BAD_VALUE -10 /**< Bad or unexpected value */ #define MPR_ERR_BUSY -11 /**< Resource is busy */ #define MPR_ERR_CANT_ACCESS -12 /**< Cannot access the file or resource */ #define MPR_ERR_CANT_ALLOCATE -13 /**< Cannot allocate resource */ #define MPR_ERR_CANT_COMPLETE -14 /**< Operation cannot complete */ #define MPR_ERR_CANT_CONNECT -15 /**< Cannot connect to network or resource */ #define MPR_ERR_CANT_CREATE -16 /**< Cannot create the file or resource */ #define MPR_ERR_CANT_DELETE -17 /**< Cannot delete the resource */ #define MPR_ERR_CANT_FIND -18 /**< Cannot find resource */ #define MPR_ERR_CANT_INITIALIZE -19 /**< Cannot initialize resource */ #define MPR_ERR_CANT_LOAD -20 /**< Cannot load the resource */ #define MPR_ERR_CANT_OPEN -21 /**< Cannot open the file or resource */ #define MPR_ERR_CANT_READ -22 /**< Cannot read from the file or resource */ #define MPR_ERR_CANT_WRITE -23 /**< Cannot write to the file or resource */ #define MPR_ERR_DELETED -24 /**< Resource has been deleted */ #define MPR_ERR_MEMORY -25 /**< Memory allocation error */ #define MPR_ERR_NETWORK -26 /**< Underlying network error */ #define MPR_ERR_NOT_INITIALIZED -27 /**< Module or resource is not initialized */ #define MPR_ERR_NOT_READY -28 /**< Resource is not ready */ #define MPR_ERR_READ_ONLY -29 /**< The operation timed out */ #define MPR_ERR_TIMEOUT -30 /**< Operation exceeded specified time allowed */ #define MPR_ERR_TOO_MANY -31 /**< Too many requests or resources */ #define MPR_ERR_WONT_FIT -32 /**< Requested operation won't fit in available space */ #define MPR_ERR_WOULD_BLOCK -33 /**< Blocking operation would block */ #define MPR_ERR_MAX -34 /* Error line number information. */ #define MPR_LINE(s) #s #define MPR_LINE2(s) MPR_LINE(s) #define MPR_LINE3 MPR_LINE2(__LINE__) #define MPR_LOC __FILE__ ":" MPR_LINE3 #define MPR_NAME(msg) msg "@" MPR_LOC #define MPR_STRINGIFY(s) #s /* Convenience define to declare a main program entry point that works for Windows, VxWorks and Unix */ #if VXWORKS #define MAIN(name, _argc, _argv, _envp) \ static int innerMain(int argc, char **argv, char **envp); \ int name(char *arg0, ...) { \ va_list args; \ char *argp, *largv[ME_MAX_ARGC]; \ int largc = 0; \ va_start(args, arg0); \ largv[largc++] = #name; \ if (arg0) { \ largv[largc++] = arg0; \ } \ for (argp = va_arg(args, char*); argp && largc < ME_MAX_ARGC; argp = va_arg(args, char*)) { \ largv[largc++] = argp; \ } \ return innerMain(largc, largv, NULL); \ } \ static int innerMain(_argc, _argv, _envp) #elif ME_WIN_LIKE #define MAIN(name, _argc, _argv, _envp) \ APIENTRY WinMain(HINSTANCE inst, HINSTANCE junk, char *command, int junk2) { \ PUBLIC int main(); \ char *largv[ME_MAX_ARGC]; \ int largc; \ largc = mprParseArgs(command, &largv[1], ME_MAX_ARGC - 1); \ largv[0] = #name; \ main(largc, largv, NULL); \ } \ int main(_argc, _argv, _envp) #else #define MAIN(name, _argc, _argv, _envp) int main(_argc, _argv, _envp) #endif #if ME_UNIX_LIKE typedef pthread_t MprOsThread; #elif ME_64 typedef int64 MprOsThread; #else typedef int MprOsThread; #endif /** Elapsed time data type. Stores time in milliseconds from some arbitrary start epoch. */ typedef Ticks MprTicks; /************************************** Debug *********************************/ /** Trigger a breakpoint. @description This routine is invoked for assertion errors from #mprAssert and errors from #mprError. It is useful in debuggers as breakpoint location for detecting errors. @ingroup Mpr @stability Stable */ PUBLIC void mprBreakpoint(void); #undef assert #if DOXYGEN /** Assert that a condition is true @param cond Boolean result of a conditional test @ingroup Mpr @stability Stable */ PUBLIC void assert(bool cond); #elif ME_MPR_DEBUG_LOGGING #undef assert #define assert(C) if (C) ; else mprAssert(MPR_LOC, #C) #else #undef assert #define assert(C) if (1) ; else {} #endif /*********************************** Thread Sync ******************************/ /** Multithreaded Synchronization Services @see MprCond MprMutex MprSpin mprAtomicAdd mprAtomicAdd64 mprAtomicBarrier mprAtomicCas mprAtomicExchange mprAtomicListInsert mprCreateCond mprCreateLock mprCreateSpinLock mprGlobalLock mprGlobalUnlock mprInitLock mprInitSpinLock mprLock mprResetCond mprSignalCond mprSignalMultiCond mprSpinLock mprSpinUnlock mprTryLock mprTrySpinLock mprUnlock mprWaitForCond mprWaitForMultiCond @stability Internal. @defgroup MprSync MprSync */ typedef struct MprSync { int dummy; } MprSync; #ifndef ME_MPR_SPIN_COUNT #define ME_MPR_SPIN_COUNT 1500 /* Windows lock spin count */ #endif /** Condition variable for single and multi-thread synchronization. Condition variables can be used to coordinate activities. These variables are level triggered in that a condition can be signalled prior to another thread waiting. Condition variables can be used when single threaded but mprServiceEvents should be called to pump events until another callback invokes mprWaitForCond. @ingroup MprSync @stability Internal. */ typedef struct MprCond { #if ME_UNIX_LIKE pthread_cond_t cv; /**< Unix pthreads condition variable */ #elif ME_WIN_LIKE HANDLE cv; /**< Windows event handle */ #elif VXWORKS SEM_ID cv; /**< Condition variable */ #else #warning "Unsupported OS in MprCond definition in mpr.h" #endif struct MprMutex *mutex; /**< Thread synchronization mutex */ volatile int triggered; /**< Value of the condition */ } MprCond; /** Create a condition lock variable. @description This call creates a condition variable object that can be used in #mprWaitForCond and #mprSignalCond calls. @ingroup MprSync @stability Stable. */ PUBLIC MprCond *mprCreateCond(void); /** Reset a condition variable. This sets the condition variable to the unsignalled condition. @param cond Condition variable object created via #mprCreateCond @ingroup MprSync @stability Stable. */ PUBLIC void mprResetCond(MprCond *cond); /** Wait for a condition lock variable. @description Wait for a condition lock variable to be signaled. If the condition is signaled before the timeout expires, this call will reset the condition variable and return. This way, it automatically resets the variable for future waiters. @param cond Condition variable object created via #mprCreateCond @param timeout Time in milliseconds to wait for the condition variable to be signaled. @return Zero if the event was signalled. Returns < 0 for a timeout. @ingroup MprSync @stability Stable. */ PUBLIC int mprWaitForCond(MprCond *cond, MprTicks timeout); /** Signal a condition lock variable. @description Signal a condition variable and set it to the \a triggered status. Existing or future caller of #mprWaitForCond will be awakened. The condition variable will be automatically reset when the waiter awakes. Should only be used for single waiters. Use mprSignalMultiCond for use with multiple waiters. \n\n This API (like nearly all MPR APIs) must only be used by MPR threads and not by non-MPR (foreign) threads. If you need to synchronize active of MPR threads with non-MPR threads, use #mprCreateEvent which can be called from foreign threads. @param cond Condition variable object created via #mprCreateCond @ingroup MprSync @stability Stable. */ PUBLIC void mprSignalCond(MprCond *cond); /** Signal a condition lock variable for use with multiple waiters. @description Signal a condition variable and set it to the \a triggered status. Existing or future callers of #mprWaitForCond will be awakened. The conditional variable will not be automatically reset and must be reset manually via mprResetCond. @param cond Condition variable object created via #mprCreateCond @ingroup MprSync @stability Stable. */ PUBLIC void mprSignalMultiCond(MprCond *cond); /** Wait for a condition lock variable for use with multiple waiters. @description Wait for a condition lock variable to be signaled. Multiple waiters are supported and the condition variable must be manually reset via mprResetCond. The condition may signaled before calling mprWaitForMultiCond. @param cond Condition variable object created via #mprCreateCond @param timeout Time in milliseconds to wait for the condition variable to be signaled. @return Zero if the event was signalled. Returns < 0 for a timeout. @ingroup MprSync @stability Stable. */ PUBLIC int mprWaitForMultiCond(MprCond *cond, MprTicks timeout); /** Multithreading lock control structure @description MprMutex is used for multithread locking in multithreaded applications. @ingroup MprSync @stability Internal. */ typedef struct MprMutex { #if ME_WIN_LIKE CRITICAL_SECTION cs; /**< Internal mutex critical section */ bool freed; /**< Mutex has been destroyed */ #elif VXWORKS SEM_ID cs; #elif ME_UNIX_LIKE pthread_mutex_t cs; #else #warning "Unsupported OS in MprMutex definition in mpr.h" #endif #if ME_DEBUG MprOsThread owner; #endif } MprMutex; /** Multithreading spin lock control structure @description MprSpin is used for multithread locking in multithreaded applications. @ingroup MprSync @stability Internal. */ typedef struct MprSpin { #if USE_MPR_LOCK MprMutex cs; #elif ME_WIN_LIKE CRITICAL_SECTION cs; /**< Internal mutex critical section */ bool freed; /**< Mutex has been destroyed */ #elif VXWORKS SEM_ID cs; #elif ME_UNIX_LIKE #if ME_COMPILER_HAS_SPINLOCK pthread_spinlock_t cs; #else pthread_mutex_t cs; #endif #else #warning "Unsupported OS in MprSpin definition in mpr.h" #endif #if ME_DEBUG MprOsThread owner; #endif } MprSpin; #undef lock #undef unlock #undef spinlock #undef spinunlock #define lock(arg) if (arg && (arg)->mutex) mprLock((arg)->mutex) #define unlock(arg) if (arg && (arg)->mutex) mprUnlock((arg)->mutex) #define spinlock(arg) if (arg) mprSpinLock((arg)->spin) #define spinunlock(arg) if (arg) mprSpinUnlock((arg)->spin) /** Create a Mutex lock object. @description This call creates a Mutex lock object that can be used in mprLock #mprTryLock and mprUnlock calls. @ingroup MprSync @stability Stable. */ PUBLIC MprMutex *mprCreateLock(void); /** Initialize a statically allocated Mutex lock object. @description This call initialized a Mutex lock object without allocation. The object can then be used used in mprLock mprTryLock and mprUnlock calls. @param mutex Reference to an MprMutex structure to initialize @returns A reference to the supplied mutex. Returns null on errors. @ingroup MprSync @stability Stable. */ PUBLIC MprMutex *mprInitLock(MprMutex *mutex); /** Attempt to lock access. @description This call attempts to assert a lock on the given \a lock mutex so that other threads calling mprLock or mprTryLock will block until the current thread calls mprUnlock. @returns Returns zero if the successful in locking the mutex. Returns a negative MPR error code if unsuccessful. @ingroup MprSync @stability Stable. */ PUBLIC bool mprTryLock(MprMutex *lock); /** Create a spin lock lock object. @description This call creates a spinlock object that can be used in mprSpinLock, and mprSpinUnlock calls. Spin locks using MprSpin are much faster than MprMutex based locks on some systems. @ingroup MprSync @stability Stable. */ PUBLIC MprSpin *mprCreateSpinLock(void); /** Initialize a statically allocated spinlock object. @description This call initialized a spinlock lock object without allocation. The object can then be used used in mprSpinLock and mprSpinUnlock calls. @param lock Reference to a static #MprSpin object. @returns A reference to the MprSpin object. Returns null on errors. @ingroup MprSync */ PUBLIC MprSpin *mprInitSpinLock(MprSpin *lock); /** Attempt to lock access on a spin lock @description This call attempts to assert a lock on the given \a spin lock so that other threads calling mprSpinLock or mprTrySpinLock will block until the current thread calls mprSpinUnlock. @returns Returns zero if the successful in locking the spinlock. Returns a negative MPR error code if unsuccessful. @ingroup MprSync @stability Stable. */ PUBLIC bool mprTrySpinLock(MprSpin *lock); /* For maximum performance, use the spin lock/unlock routines macros */ #if !ME_DEBUG #define ME_USE_LOCK_MACROS 1 #endif #if ME_USE_LOCK_MACROS && !DOXYGEN /* Spin lock macros */ #if ME_UNIX_LIKE && ME_COMPILER_HAS_SPINLOCK #define mprSpinLock(lock) if (lock) pthread_spin_lock(&((lock)->cs)) #define mprSpinUnlock(lock) if (lock) pthread_spin_unlock(&((lock)->cs)) #elif ME_UNIX_LIKE #define mprSpinLock(lock) if (lock) pthread_mutex_lock(&((lock)->cs)) #define mprSpinUnlock(lock) if (lock) pthread_mutex_unlock(&((lock)->cs)) #elif ME_WIN_LIKE #define mprSpinLock(lock) if (lock && (!((MprSpin*)(lock))->freed)) EnterCriticalSection(&((lock)->cs)) #define mprSpinUnlock(lock) if (lock) LeaveCriticalSection(&((lock)->cs)) #elif VXWORKS #define mprSpinLock(lock) if (lock) semTake((lock)->cs, WAIT_FOREVER) #define mprSpinUnlock(lock) if (lock) semGive((lock)->cs) #endif /* Lock macros */ #if ME_UNIX_LIKE #define mprLock(lock) if (lock) pthread_mutex_lock(&((lock)->cs)) #define mprUnlock(lock) if (lock) pthread_mutex_unlock(&((lock)->cs)) #elif ME_WIN_LIKE #define mprLock(lock) if (lock && !(((MprSpin*)(lock))->freed)) EnterCriticalSection(&((lock)->cs)) #define mprUnlock(lock) if (lock) LeaveCriticalSection(&((lock)->cs)) #elif VXWORKS #define mprLock(lock) if (lock) semTake((lock)->cs, WAIT_FOREVER) #define mprUnlock(lock) if (lock) semGive((lock)->cs) #endif #else /** Lock access. @description This call asserts a lock on the given \a lock mutex so that other threads calling mprLock will block until the current thread calls mprUnlock. @ingroup MprSync @stability Stable. */ PUBLIC void mprLock(MprMutex *lock); /** Unlock a mutex. @description This call unlocks a mutex previously locked via mprLock or mprTryLock. @ingroup MprSync @stability Stable. */ PUBLIC void mprUnlock(MprMutex *lock); /** Lock a spinlock. @description This call asserts a lock on the given \a spinlock so that other threads calling mprSpinLock will block until the curren thread calls mprSpinUnlock. @ingroup MprSync @stability Stable. */ PUBLIC void mprSpinLock(MprSpin *lock); /** Unlock a spinlock. @description This call unlocks a spinlock previously locked via mprSpinLock or mprTrySpinLock. @ingroup MprSync @stability Stable. */ PUBLIC void mprSpinUnlock(MprSpin *lock); #endif /** Globally lock the application. @description This call asserts the application global lock so that other threads calling mprGlobalLock will block until the current thread calls mprGlobalUnlock. WARNING: Use this API very sparingly. @ingroup MprSync @stability Stable. */ PUBLIC void mprGlobalLock(void); /** Unlock the global mutex. @description This call unlocks the global mutex previously locked via mprGlobalLock. @ingroup MprSync @stability Stable. */ PUBLIC void mprGlobalUnlock(void); /* Lock free primitives */ /* AtomicBarrier memory models */ #if ME_UNIX_LIKE #define MPR_ATOMIC_RELAXED __ATOMIC_RELAXED #define MPR_ATOMIC_CONSUME __ATOMIC_CONSUME #define MPR_ATOMIC_ACQUIRE __ATOMIC_ACQUIRE #define MPR_ATOMIC_RELEASE __ATOMIC_RELEASE #define MPR_ATOMIC_ACQ_REL __ATOMIC_ACQ_REL #define MPR_ATOMIC_SEQUENTIAL __ATOMIC_SEQ_CST #else #define MPR_ATOMIC_RELAXED 0 #define MPR_ATOMIC_CONSUME 1 #define MPR_ATOMIC_ACQUIRE 2 #define MPR_ATOMIC_RELEASE 3 #define MPR_ATOMIC_ACQ_REL 4 #define MPR_ATOMIC_SEQUENTIAL 5 #endif /** Open and initialize the atomic subystem @ingroup MprSync @stability Stable. */ PUBLIC void mprAtomicOpen(void); /** Apply a full (read+write) memory barrier @param model Memory model. Set to MPR_ATOMIC_RELAXED, MPR_ATOMIC_CONSUME, MPR_ATOMIC_ACQUIRE, MPR_ATOMIC_RELEASE, MPR_ATOMIC_ACQREL, MPR_ATOMIC_SEQUENTIAL @ingroup MprSync @stability Evolving. */ PUBLIC void mprAtomicBarrier(int model); /** Atomic list insertion. Inserts "item" at the "head" of the list. The "link" field is the next field in item. This is a lock-free function @param head list head @param link Reference to the list head link field @param item Item to insert @ingroup MprSync @stability Stable */ PUBLIC void mprAtomicListInsert(void **head, void **link, void *item); /** Atomic Compare and Swap. This is a lock free function. @param target Address of the target word to swap @param expected Expected value of the target @param value New value to store at the target @return TRUE if the swap was successful @ingroup MprSync @stability Stable */ PUBLIC int mprAtomicCas(void * volatile * target, void *expected, cvoid *value); /** Atomic Add. This is a lock free function. @param target Address of the target word to add to. @param value Value to add to the target @ingroup MprSync @stability Stable. */ PUBLIC void mprAtomicAdd(volatile int *target, int value); /** Atomic 64 bit Add. This is a lock free function. @param target Address of the target word to add to. @param value Value to add to the target @ingroup MprSync @stability Stable. */ PUBLIC void mprAtomicAdd64(volatile int64 *target, int64 value); #if ME_COMPILER_HAS_ATOMIC #define mprAtomicLoad(ptr, ret, model) __atomic_load(ptr, ret, model) #define mprAtomicStore(ptr, valptr, model) __atomic_store(ptr, valptr, model) #else #define mprAtomicLoad(ptr, ret, model) \ if (1) { \ mprAtomicBarrier(model); \ *ret = *(ptr); \ } else #define mprAtomicStore(ptr, valptr, model) \ if (1) { \ mprAtomicBarrier(model); \ *ptr = *(valptr); \ } else #endif /********************************* Memory Allocator ***************************/ /* Allocator debug and stats selection To set via configure: configure --set mpr.alloc.check=true configure --set mpr.alloc.cache=NNN configure --set mpr.alloc.quota=NNN */ #if ME_MPR_ALLOC_CHECK #ifndef ME_MPR_ALLOC_DEBUG #define ME_MPR_ALLOC_DEBUG 1 /**< Fill blocks, verifies block integrity, block names */ #endif #ifndef ME_MPR_ALLOC_STATS #define ME_MPR_ALLOC_STATS 1 /**< Include memory statistics */ #endif #ifndef ME_MPR_ALLOC_STACK #define ME_MPR_ALLOC_STACK 1 /**< Monitor stack usage */ #endif #ifndef ME_MPR_ALLOC_TRACE #define ME_MPR_ALLOC_TRACE 0 /**< Trace to stdout */ #endif #else #ifndef ME_MPR_ALLOC_DEBUG #define ME_MPR_ALLOC_DEBUG 0 #endif #ifndef ME_MPR_ALLOC_STATS #define ME_MPR_ALLOC_STATS 0 #endif #ifndef ME_MPR_ALLOC_STACK #define ME_MPR_ALLOC_STACK 0 #endif #ifndef ME_MPR_ALLOC_TRACE #define ME_MPR_ALLOC_TRACE 0 /**< Trace to stdout */ #endif #endif /* Allocator Tunables */ #ifndef ME_MPR_ALLOC_CACHE /* Try to cache at least this amount in the heap free queues */ #if ME_TUNE_SIZE #define ME_MPR_ALLOC_CACHE 0 #elif ME_TUNE_SPEED #define ME_MPR_ALLOC_CACHE (1 * 1024 * 1024) /* 1MB */ #else #define ME_MPR_ALLOC_CACHE ME_MPR_ALLOC_REGION_SIZE #endif #endif #ifndef ME_MPR_ALLOC_LEVEL #define ME_MPR_ALLOC_LEVEL 7 /* Emit mark/sweek elapsed time at this level */ #endif #if ME_COMPILER_HAS_MMU #define ME_MPR_ALLOC_VIRTUAL 1 /* Use virtual memory allocations */ #else #define ME_MPR_ALLOC_VIRTUAL 0 /* Use malloc() for region allocations */ #endif #ifndef ME_MPR_ALLOC_QUOTA #if ME_TUNE_SIZE #define ME_MPR_ALLOC_QUOTA (100 * 1024) /* Allocations before a GC. Scaled by workers/2 */ #else #define ME_MPR_ALLOC_QUOTA (200 * 1024) #endif #endif #ifndef ME_MPR_ALLOC_REGION_SIZE #define ME_MPR_ALLOC_REGION_SIZE (256 * 1024) /* Memory region allocation chunk size */ #endif #ifndef ME_MPR_ALLOC_ALIGN_SHIFT /* Allocated block alignment expressed as a bit shift. The default alignment is set so that allocated memory can be used for doubles. NOTE: SSE and AltiVec instuctions may require 16 byte alignment. */ #if !ME_64 && !(ME_CPU_ARCH == ME_CPU_MIPS) #define ME_MPR_ALLOC_ALIGN_SHIFT 3 /* 8 byte alignment */ #else #define ME_MPR_ALLOC_ALIGN_SHIFT 3 #endif #endif #define ME_MPR_ALLOC_ALIGN (1 << ME_MPR_ALLOC_ALIGN_SHIFT) /* The allocator (by default) is limited to individual allocations of 4GB (32 bits). This enables memory blocks to be optimally aligned with minimal overhead. Define ME_MPR_ALLOC_BIG on 64-bit systems to enable allocating blocks greater than 4GB. */ #if ME_MPR_ALLOC_BIG && ME_64 typedef uint64 MprMemSize; #else typedef uint MprMemSize; #endif #define MPR_ALLOC_MAX ((MprMemSize) - ME_MPR_ALLOC_ALIGN) /** Memory Allocation Service. @description The MPR provides an application specific memory allocator to use instead of malloc. This allocator is tailored to the needs of embedded applications and is faster than most general purpose malloc allocators. It is deterministic and allocates and frees in constant time O(1). It exhibits very low fragmentation and accurate coalescing. \n\n The allocator uses a garbage collector for freeing unused memory. The collector is a cooperative, non-compacting, parallel collector. The allocator is optimized for frequent allocations of small blocks (< 4K) and uses a scheme of free queues for fast allocation. Allocations are aligned as specified by ME_MPR_ALLOC_ALIGN_SHIFT. This is typically 16 byte aligned for 64-bit systems and 8 byte aligned for 32-bit systems. The allocator will return unused memory back to the O/S to minimize application memory footprint. \n\n The allocator handles memory allocation errors globally. The application may configure a memory limit so that memory depletion can be proactively detected and handled before memory allocations actually fail. \n\n A memory block that is being used must be marked as active to prevent the garbage collector from reclaiming it. To mark a block as active, #mprMark must be called during each garbage collection cycle. When allocating non-temporal memory blocks, a manager callback can be specified via #mprAllocObj. This manager routine will be called by the collector so that dependent memory blocks can be marked as active. \n\n The collector performs the marking phase by invoking the manager routines for a set of root blocks. A block can be added to the set of roots by calling #mprAddRoot. Each root's manager routine will mark other blocks which will cause their manager routines to run and so on, until all active blocks have been marked. Non-marked blocks can then safely be reclaimed as garbage. A block may alternatively be permanently marked as active by calling #mprHold. \n\n The mark phase begins when all threads explicitly "yield" to the garbage collector. This cooperative approach ensures that user threads will not inadvertendly loose allocated blocks to the collector. Once all active blocks are marked, user threads are resumed and the garbage sweeper frees unused blocks in parallel with user threads. @stability Internal @defgroup MprMem MprMem @see MprFreeMem MprHeap MprManager MprMemNotifier MprRegion mprAddRoot mprAlloc mprAllocMem mprAllocObj mprAllocZeroed mprCreateMemService mprDestroyMemService mprEnableGC mprGetBlockSize mprGetMem mprGetMemStats mprGetMpr mprGetPageSize mprHasMemError mprHold mprIsPathContained mprIsValid mprMark mprMemcmp mprMemcpy mprMemdup mprPrintMem mprRealloc mprRelease mprRemoveRoot mprGC mprResetMemError mprRevive mprSetAllocLimits mprSetManager mprSetMemError mprSetMemLimits mprSetMemNotifier mprSetMemPolicy mprSetName mprVerifyMem mprVirtAlloc mprVirtFree */ typedef struct MprMem { MprMemSize size; /**< Size of the block in bytes. Not the amount requested by the user which may be smaller. This is a 32-bit quantity on all systems unless ME_MPR_ALLOC_BIG is defined and then it will be 64 bits. */ uchar qindex; /**< Freeq index. Always less than 512 queues. */ uchar eternal; /**< Immune from GC. Implemented as a byte to be atomic */ uchar mark; /**< GC mark indicator. Toggled for each GC pass by mark() when thread yielded. */ /* Bits for fields only updated by mark/sweeper. Must not use bits for fields updated by multiple threads. */ uchar free: 1; /**< Block not in use */ uchar first: 1; /**< Block is first block in region */ uchar hasManager: 1; /**< Has manager function. Set at block init. */ uchar fullRegion: 1; /**< Block is an entire region - never on free queues . */ #if ME_MPR_ALLOC_DEBUG /* This increases the size of MprMem from 8 bytes to 16 bytes on 32-bit systems and 24 bytes on 64 bit systems */ cchar *name; /**< Debug name */ ushort magic; /**< Unique signature */ ushort seqno; /**< Allocation sequence number */ #if ME_64 uchar filler[4]; #endif #endif } MprMem; /** Block structure when on a free list. This overlays MprMem and replaces sibling and children with forw/back The implies a minimum memory block size of 16 bytes. @ingroup MprMem @stability Internal. */ typedef struct MprFreeMem { MprMem blk; struct MprFreeMem *prev; /**< Previous free block */ struct MprFreeMem *next; /**< Next free block */ } MprFreeMem; /** Free queue head structure. These must share the same layout as MprFreeMem for the prev/next pointers. */ typedef struct MprFreeQueue { MprMem blk; /**< Unused in queue head */ struct MprFreeMem *prev; /**< Previous free block */ struct MprFreeMem *next; /**< Next free block */ MprSpin lock; /**< Queue lock-free lock */ uint count; /**< Number of blocks on the queue */ MprMemSize minSize; /**< Minimum size of blocks in queue. This is the user block size sans MprMem header. */ } MprFreeQueue; #define MPR_ALLOC_ALIGN(x) (((x) + ME_MPR_ALLOC_ALIGN - 1) & ~(ME_MPR_ALLOC_ALIGN - 1)) #define MPR_ALLOC_MIN_BLOCK sizeof(MprFreeMem) #define MPR_ALLOC_MAX_BLOCK (ME_MPR_ALLOC_REGION_SIZE - sizeof(MprRegion)) #define MPR_ALLOC_MIN_SPLIT (32 + sizeof(MprMem)) #define MPR_ALLOC_MAGIC 0xe813 #define MPR_PAGE_ALIGN(x, psize) ((((ssize) (x)) + ((ssize) (psize)) - 1) & ~(((ssize) (psize)) - 1)) #define MPR_PAGE_ALIGNED(x, psize) ((((ssize) (x)) % ((ssize) (psize))) == 0) /* The allocator has a set of free queues to hold blocks of a given size range. Higher queues progressively address a larger range of block sizes. This mapping is achived by taking the most significant QBIT bits of the requested block size and then discarding the top bit (MSB). All combinations of the REST bits are mapped to the same queue. +-------------------------------+ | QBits | REST | +-------------------------------+ | 0 | 1 | X | X | X | ......... | +-------------------------------+ | 1 | X | X | X | ............. | +-------------------------------+ A bitmap records for each queue whether it has any free blocks in the queue. Note: qindex 2 is the first queue used because the minimum block size is sizeof(MprFreeMem) */ #define MPR_ALLOC_QBITS_SHIFT 2 #define MPR_ALLOC_NUM_QBITS (1 << MPR_ALLOC_QBITS_SHIFT) /* Should set region shift to log(ME_MPR_ALLOC_REGION_SIZE) We don't expect users to tinker with these */ #if ME_MPR_ALLOC_REGION_SIZE == (128 * 1024) #define ME_MPR_ALLOC_REGION_SHIFT 18 #elif ME_MPR_ALLOC_REGION_SIZE == (256 * 1024) #define ME_MPR_ALLOC_REGION_SHIFT 19 #elif ME_MPR_ALLOC_REGION_SIZE == (512 * 1024) #define ME_MPR_ALLOC_REGION_SHIFT 20 #else #define ME_MPR_ALLOC_REGION_SHIFT 24 #endif #define MPR_ALLOC_NUM_QUEUES ((ME_MPR_ALLOC_REGION_SHIFT - ME_MPR_ALLOC_ALIGN_SHIFT - MPR_ALLOC_QBITS_SHIFT) * \ MPR_ALLOC_NUM_QBITS) #define MPR_ALLOC_BITMAP_BITS BITS(size_t) #define MPR_ALLOC_NUM_BITMAPS ((MPR_ALLOC_NUM_QUEUES + MPR_ALLOC_BITMAP_BITS - 1) / MPR_ALLOC_BITMAP_BITS) /* Pointer to MprMem and vice-versa */ #define MPR_GET_PTR(bp) ((void*) (((char*) (bp)) + sizeof(MprMem))) #define MPR_GET_MEM(ptr) ((MprMem*) (((char*) (ptr)) - sizeof(MprMem))) #define MPR_GET_USIZE(mp) ((size_t) (mp->size - sizeof(MprMem) - (mp->hasManager * sizeof(void*)))) /* Manager callback is stored in the padding region at the end of the user memory in the block. */ #define MPR_MANAGER_SIZE 1 #define MPR_MANAGER_OFFSET 1 #define MPR_MEM_PAD_PTR(mp, offset) ((void*) (((char*) mp) + mp->size - ((offset) * sizeof(void*)))) #define GET_MANAGER(mp) ((MprManager) (*(void**) ((MPR_MEM_PAD_PTR(mp, MPR_MANAGER_OFFSET))))) #define SET_MANAGER(mp, fn) do { \ *((MprManager*) MPR_MEM_PAD_PTR(mp, MPR_MANAGER_OFFSET)) = fn ; \ mp->hasManager = 1; \ } while (0); /* Manager callback flags */ #define MPR_MANAGE_FREE 0x1 /**< Block being freed. Free dependant resources */ #define MPR_MANAGE_MARK 0x2 /**< Block being marked by GC. Mark dependant resources */ /* VirtAloc flags */ #if ME_WIN_LIKE || VXWORKS #define MPR_MAP_READ 0x1 #define MPR_MAP_WRITE 0x2 #define MPR_MAP_EXECUTE 0x4 #else #define MPR_MAP_READ PROT_READ #define MPR_MAP_WRITE PROT_WRITE #define MPR_MAP_EXECUTE PROT_EXEC #endif #if ME_MPR_ALLOC_DEBUG #define MPR_CHECK_BLOCK(bp) mprCheckBlock(bp) #define MPR_VERIFY_MEM() if (MPR->heap->verify) { mprVerifyMem(); } else {} #else #define MPR_CHECK_BLOCK(bp) #define MPR_VERIFY_MEM() #endif /* Memory depletion policy (mprSetAllocPolicy) */ #define MPR_ALLOC_POLICY_NOTHING 0 /**< Do nothing */ #define MPR_ALLOC_POLICY_PRUNE 1 /**< Prune all non-essential memory and continue */ #define MPR_ALLOC_POLICY_RESTART 2 /**< Gracefully restart the app */ #define MPR_ALLOC_POLICY_EXIT 3 /**< Exit the app cleanly */ #define MPR_ALLOC_POLICY_ABORT 4 /**< Abort the app and dump core */ /* MprMemNotifier cause argument */ #define MPR_MEM_WARNING 0x1 /**< Memory use exceeds warnHeap level limit */ #define MPR_MEM_LIMIT 0x2 /**< Memory use exceeds memory limit - invoking policy */ #define MPR_MEM_FAIL 0x4 /**< Memory allocation failed - immediate exit */ #define MPR_MEM_TOO_BIG 0x8 /**< Memory allocation request is too big - immediate exit */ /** Memory allocation error callback. Notifiers are called if a low memory condition exists. @param cause Set to the cause of the memory error. Set to #MPR_MEM_WARNING if the allocation will exceed the warnHeap limit. Set to #MPR_MEM_LIMIT if it would exceed the maxHeap memory limit. Set to #MPR_MEM_FAIL if the allocation failed. Set to #MPR_MEM_TOO_BIG if the allocation block size is too large. Allocations will be rejected for MPR_MEM_FAIL and MPR_MEM_TOO_BIG, otherwise the allocations will proceed and the memory notifier will be invoked. @param policy Memory depletion policy. Set to one of #MPR_ALLOC_POLICY_NOTHING, #MPR_ALLOC_POLICY_PRUNE, #MPR_ALLOC_POLICY_RESTART, #MPR_ALLOC_POLICY_EXIT or #MPR_ALLOC_POLICY_ABORT. @param size Size of the allocation that triggered the low memory condition. @param total Total memory currently in use @ingroup MprMem @stability Stable. */ typedef void (*MprMemNotifier)(int cause, int policy, size_t size, size_t total); /** Mpr memory block manager prototype @param ptr Any memory context allocated by the MPR. @ingroup MprMem @stability Stable. */ typedef void (*MprManager)(void *ptr, int flags); #if ME_MPR_ALLOC_DEBUG /* The location stats table tracks the source code location responsible for each allocation Very costly. Don't use except for debug. */ #define MPR_TRACK_HASH 2053 /* Size of location name hash */ #define MPR_TRACK_NAMES 8 /* Length of collision chain */ typedef struct MprLocationStats { size_t total; /* Total allocations for this location */ int count; /* Count of allocations for this location */ cchar *names[MPR_TRACK_NAMES]; /* Manager names */ } MprLocationStats; #endif /** Memory allocator statistics @ingroup MprMem @stability Internal. */ typedef struct MprMemStats { int inMemException; /**< Recursive protect */ uint cpuCores; /**< Number of CPU cores */ uint pageSize; /**< System page size */ uint heapRegions; /**< Heap region count */ uint sweeps; /**< Number of GC sweeps */ uint64 cpuUsage; /**< Process CPU usage in ticks */ uint64 cacheHeap; /**< Heap cache. Try to keep at least this amount in the free queues */ uint64 bytesAllocated; /**< Bytes currently allocated. Includes active and free. */ uint64 bytesAllocatedPeak; /**< Max ever bytes allocated */ uint64 bytesFree; /**< Bytes currently free and retained in the heap queues */ uint64 errors; /**< Allocation errors */ uint64 lowHeap; /**< Low memory level at which to initiate a collection */ uint64 maxHeap; /**< Max memory that can be allocated */ uint64 ram; /**< System RAM size in bytes */ uint64 rss; /**< OS calculated memory resident set size in bytes */ uint64 user; /**< System user RAM size in bytes (excludes kernel) */ uint64 warnHeap; /**< Warn if heap size exceeds this level */ uint64 swept; /**< Number of blocks swept */ uint64 sweptBytes; /**< Number of bytes swept */ #if ME_MPR_ALLOC_STATS /* Extended memory stats */ uint64 allocs; /**< Count of times a block was split Calls to allocate memory from the O/S */ uint64 cached; /**< Count of blocks that are cached rather then joined with adjacent blocks */ uint64 compacted; /**< Count of blocks that are compacted during compacting sweeps */ uint64 collections; /**< Number of GC collections */ uint64 freed; /**< Bytes freed in last sweep */ uint64 joins; /**< Count of times a block was joined (coalesced) with its neighbours */ uint64 markVisited; /**< Number of blocks examined for marking */ uint64 marked; /**< Number of blocks marked */ uint64 race; /**< Another thread raced for a block and won */ uint64 requests; /**< Count of memory requests */ uint64 reuse; /**< Count of times a block was reused from a free queue */ uint64 retries; /**< Queue retries */ uint64 qrace; /**< Count of times a queue was empty - racing with another thread */ uint64 splits; /**< Count of times a block was split */ uint64 sweepVisited; /**< Number of blocks examined for sweeping */ uint64 trys; /**< Attempts to acquire a freeq */ uint64 tryFails; /** Acquire a freeq fail count */ uint64 unpins; /**< Count of times a block was unpinned and released back to the O/S */ #endif #if ME_MPR_ALLOC_DEBUG MprLocationStats locations[MPR_TRACK_HASH]; /* Per location allocation stats */ #endif } MprMemStats; /** Memmory regions allocated from the O/S @ingroup MprMem @stability Internal. */ typedef struct MprRegion { struct MprRegion *next; /**< Next region */ MprMem *start; /**< Start of region data */ MprMem *end; /**< End of region data */ size_t size; /**< Size of region including region header */ int freeable; /**< Set to true when completely unused */ } MprRegion; /** Memory allocator heap @ingroup MprMem @stability Internal. */ typedef struct MprHeap { MprFreeQueue freeq[MPR_ALLOC_NUM_QUEUES]; /**< Heap free queues */ size_t bitmap[MPR_ALLOC_NUM_BITMAPS]; /* Freeq bit map. Must be size_t for cas() */ struct MprList *roots; /**< List of GC root objects */ MprMemStats stats; /**< Memory allocation statistics */ MprMemNotifier notifier; /**< Memory allocation failure callback */ MprCond *gcCond; /**< GC sleep cond var */ MprRegion *regions; /**< List of memory regions */ struct MprThread *sweeper; /**< GC sweeper thread */ int allocPolicy; /**< Memory allocation depletion policy */ int regionSize; /**< Memory allocation region size */ int compact; /**< Next GC sweep should do a full compact */ int collecting; /**< Manual GC is running */ int freedBlocks; /**< True if the last sweep freed blocks */ int flags; /**< GC operational control flags */ int from; /**< Eligible mprCollectGarbage flags */ int gcEnabled; /**< GC is enabled */ int gcRequested; /**< GC has been requested */ int hasError; /**< Memory allocation error */ int marking; /**< Actually marking objects now */ int mustYield; /**< Threads must yield for GC which is due */ int nextSeqno; /**< Next sequence number */ int pageSize; /**< System page size */ int printStats; /**< Print diagnostic heap statistics */ uint64 priorFree; /**< Last sweep free memory */ uint64 priorWorkDone; /**< Prior workDone before last sweep */ int scribble; /**< Scribble over freed memory (slow) */ int sweeping; /**< Actually sweeping objects now */ int track; /**< Track memory allocations (requires ME_MPR_ALLOC_DEBUG) */ int verify; /**< Verify memory contents (very slow) */ uint64 workDone; /**< Count of allocations weighted by block size */ uint64 workQuota; /**< Quota of work done before idle GC worthwhile */ uchar mark; /**< Mark version */ } MprHeap; /** Create and initialize the Memory service @description Called internally by the MPR. Should not be called by users. @param manager Memory manager to manage the Mpr object @param flags Memory initialization control flags @return The Mpr control structure @ingroup MprMem @stability Internal. */ PUBLIC struct Mpr *mprCreateMemService(MprManager manager, int flags); /* Flags for mprAllocMem */ #define MPR_ALLOC_MANAGER 0x1 /**< Reserve room for a manager */ #define MPR_ALLOC_ZERO 0x2 /**< Zero memory */ #define MPR_ALLOC_HOLD 0x4 /**< Allocate and hold -- immune from GC until mprRelease */ #define MPR_ALLOC_PAD_MASK 0x1 /**< Flags that impact padding */ /** Allocate a block of memory. @description This is the lowest level of memory allocation routine. Memory is freed via the garbage collector. To protect an active memory block memory block from being reclaimed, it must have a reference to it. Memory blocks can specify a manager routine via #mprAllocObj. The manager is is invoked by the garbage collector to "mark" dependant active blocks. Marked blocks will not be reclaimed by the garbage collector. \n\n This function can be called by foreign (non Mpr) threads provided you use the MPR_ALLOC_HOLD flag so that the memory will be preserved until you call mprRelease on the memory block. This is important, as without the MPR_ALLOC_HOLD flag, the garbage collector could run immediately after calling mprAlloc and collect the memory. When used in an Mpr thread, the garbage collector cannot run until your thread calls #mprYield and so the memory is safe from immediate collection. @param size Size of the memory block to allocate. @param flags Allocation flags. Supported flags include: MPR_ALLOC_MANAGER to reserve room for a manager callback and MPR_ALLOC_ZERO to zero allocated memory. Use MPR_ALLOC_HOLD to return memory immune from GC. Must use this flag if calling from a foreign thread. Use #mprRelease to release back to the system. @return Returns a pointer to the allocated block. If memory is not available the memory exhaustion handler specified via mprCreate will be called to allow global recovery. @remarks Do not mix calls to malloc and mprAlloc. @ingroup MprMem @stability Stable. */ PUBLIC void *mprAllocMem(size_t size, int flags); /** Return the process CPU usage. @returns The total number of ticks of cpu usage since process tart @ingroup MprMem @stability Stable */ PUBLIC uint64 mprGetCPU(void); /** Return the current allocation memory statistics block @returns a reference to the allocation memory statistics. Do not modify its contents. @ingroup MprMem @stability Internal. */ PUBLIC MprMemStats *mprGetMemStats(void); /** Return the amount of memory currently used by the application. On Unix, this returns the total application memory size including code, stack, data and heap. On Windows, VxWorks and other operatings systems, it returns the amount of allocated heap memory. @returns the amount of memory used by the application in bytes. @ingroup MprMem @stability Stable. */ PUBLIC size_t mprGetMem(void); /** Get the current O/S virtual page size @returns the page size in bytes @ingroup MprMem @stability Stable. */ PUBLIC int mprGetPageSize(void); /** Get the allocated size of a memory block @param ptr Any memory allocated by mprAlloc @returns the block size in bytes @ingroup MprMem @stability Internal. */ PUBLIC size_t mprGetBlockSize(cvoid *ptr); /** Determine if the MPR has encountered memory allocation errors. @description Returns true if the MPR has had a memory allocation error. Allocation errors occur if any memory allocation would cause the application to exceed the configured warnHeap limit, or if any O/S memory allocation request fails. @return TRUE if a memory allocation error has occurred. Otherwise returns FALSE. @ingroup MprMem @stability Stable. */ PUBLIC bool mprHasMemError(void); /** Test is a pointer is a valid memory context. This is used to test if a block has been dynamically allocated. @param ptr Any memory context allocated by mprAlloc or mprCreate. @ingroup MprMem @stability Internal. */ PUBLIC int mprIsValid(cvoid *ptr); /** Compare two byte strings. @description Safely compare two byte strings. This is a safe replacement for memcmp. @param b1 Pointer to the first byte string. @param b1Len Length of the first byte string. @param b2 Pointer to the second byte string. @param b2Len Length of the second byte string. @return Returns zero if the byte strings are identical. Otherwise returns -1 if the first string is less than the second. Returns 1 if the first is greater than the first. @ingroup MprMem @stability Stable. */ PUBLIC int mprMemcmp(cvoid *b1, size_t b1Len, cvoid *b2, size_t b2Len); /** Safe copy for a block of data. @description Safely copy a block of data into an existing memory block. The call ensures the destination block is not overflowed and returns the size of the block actually copied. This is similar to memcpy, but is a safer alternative. @param dest Pointer to the destination block. @param destMax Maximum size of the destination block. @param src Block to copy @param nbytes Size of the source block @return Returns the number of characters in the allocated block. @ingroup MprMem @stability Stable. */ PUBLIC size_t mprMemcpy(void *dest, size_t destMax, cvoid *src, size_t nbytes); /** Duplicate a block of memory. @description Copy a block of memory into a newly allocated block. @param ptr Pointer to the block to duplicate. @param size Size of the block to copy. @return Returns an allocated block. @ingroup MprMem @stability Stable. */ PUBLIC void *mprMemdup(cvoid *ptr, size_t size); #define MPR_MEM_DETAIL 0x1 /* Print a detailed report */ /** Print a memory usage report to stdout @param msg Prefix message to the report @param flags Set to MPR_MEM_DETAIL for a detailed memory report @ingroup MprMem @stability Internal. */ PUBLIC void mprPrintMem(cchar *msg, int flags); /** Reallocate a block @description Reallocates a block increasing its size. If the specified size is less than the current block size, the call will ignore the request and simply return the existing block. The new memory portion is not zeroed. @param ptr Memory to reallocate. If NULL, call malloc. @param size New size of the required memory block. @return Returns a pointer to the allocated block. If memory is not available the memory exhaustion handler specified via mprCreate will be called to allow global recovery. @remarks Do not mix calls to realloc and mprRealloc. @ingroup MprMem @stability Stable. */ PUBLIC void *mprRealloc(void *ptr, size_t size); /** Reset the memory allocation error flag @description Reset the alloc error flag triggered. @ingroup MprMem @stability Internal. */ PUBLIC void mprResetMemError(void); /* Revive a memory block scheduled for collection. This should only ever be called in the manager routine for a block when the manage flags parameter is set to MPR_MANAGE_FREE. Reviving a block aborts its collection. @param ptr Reference to an allocated memory block. @internal @stability Internal. */ PUBLIC void mprRevive(cvoid* ptr); /** Define a memory notifier @description A notifier callback will be invoked for memory allocation errors for the given memory context. @param cback Notifier callback function @ingroup MprMem @stability Stable. */ PUBLIC void mprSetMemNotifier(MprMemNotifier cback); /** Set an memory allocation error condition on a memory context. This will set an allocation error condition on the given context and all its parents. This way, you can test the ultimate parent and detect if any memory allocation errors have occurred. @ingroup MprMem @stability Stable. */ PUBLIC void mprSetMemError(void); /** Configure the application memory limits @description Configure memory limits to constrain memory usage by the application. The memory allocation subsystem will check these limits before granting memory allocation requrests. The warnHeap is a soft limit that if exceeded will invoke the memory allocation callback, but will still honor the request. The maximum limit is a hard limit. The MPR will prevent allocations which exceed this maximum. The memory callback handler is defined via the #mprCreate call. @param warnHeap Soft memory limit. If exceeded, the request will be granted, but the memory handler will be invoked. to issue a warning and potentially take remedial acation. If -1, then do not update the warnHeap. @param maximum Hard memory limit. If exceeded, the request will not be granted, and the memory handler will be invoked. If -1, then do not update the maximum. @param cache Heap cache. Try to keep at least this amount of memory in the heap free queues If -1, then do not update the cache. @ingroup MprMem @stability Stable. */ PUBLIC void mprSetMemLimits(ssize warnHeap, ssize maximum, ssize cache); /** Set the memory allocation policy for when allocations fail. @param policy Set to MPR_ALLOC_POLICY_EXIT for the application to immediately exit on memory allocation errors. Set to MPR_ALLOC_POLICY_RESTART to restart the appplication on memory allocation errors. @ingroup MprMem @stability Stable. */ PUBLIC void mprSetMemPolicy(int policy); /** Update the manager for a block of memory. @description This call updates the manager for a block of memory allocated via mprAllocWithManager. @param ptr Memory to free. If NULL, take no action. @param manager Manager function to invoke when the memory is released. @return Returns the original object @ingroup MprMem @stability Stable. */ PUBLIC void *mprSetManager(void *ptr, MprManager manager); /** Memory virtual memory into the applications address space. @param size of virtual memory to map. This size will be rounded up to the nearest page boundary. @param mode Mask set to MPR_MAP_READ | MPR_MAP_WRITE @ingroup MprMem @stability Stable. */ PUBLIC void *mprVirtAlloc(size_t size, int mode); /** Free (unpin) a mapped section of virtual memory @param ptr Virtual address to free. Should be page aligned @param size Size of memory to free in bytes @ingroup MprMem @stability Stable. */ PUBLIC void mprVirtFree(void *ptr, size_t size); /** Allocate a "permanent" block of memory that is not subject GC. @description This allocates a block of memory using the MPR allocator. It then calls mprHold on the block. to prevent GC from freeing the block. @param size Size of the memory block to allocate. @return Returns a pointer to the allocated block. If memory is not available the memory exhaustion handler specified via mprCreate will be called to allow global recovery. @remarks Do not mix calls to palloc and malloc. @ingroup MprMem @stability Stable */ PUBLIC void *palloc(size_t size); /** Free a "permanent" block of memory allocated via "palloc". @description This releases a block of memory allocated via "palloc" to be collected by the garbage collector. @param ptr Pointer to the block @remarks Do not mix calls to pfree and free. @ingroup MprMem @stability Stable */ PUBLIC void pfree(void *ptr); /** Reallocate a "permanent" block of memory allocated via "palloc". This function should not be used by foreign (non Mpr) threads. @description This increases the size of a block of memory allocated via "palloc". @param ptr Pointer to the block @param size New block size @return Returns a pointer to the allocated block. If memory is not available the memory exhaustion handler specified via mprCreate will be called to allow global recovery. @remarks Do not mix calls to prealloc and malloc. @ingroup MprMem @stability Stable */ PUBLIC void *prealloc(void *ptr, size_t size); /** Return the size of the block. This may be larger than what was originally requested. This function should not be used by foreign (non Mpr) threads. @param ptr Pointer to the block @return Size of the allocated block. @ingroup MprMem @stability Stable */ PUBLIC size_t psize(void *ptr); /* Macros. When building documentation (DOXYGEN), define pretend function defintions for the documentation. */ /* In debug mode, all memory blocks can have a debug name */ #if ME_MPR_ALLOC_DEBUG PUBLIC void *mprSetName(void *ptr, cchar *name); PUBLIC void *mprCopyName(void *dest, void *src); #define mprGetName(ptr) (MPR_GET_MEM(ptr)->name) PUBLIC void *mprSetAllocName(void *ptr, cchar *name); #else #define mprCopyName(dest, src) #define mprGetName(ptr) "" #define mprSetAllocName(ptr, name) ptr #define mprSetName(ptr, name) #endif #define mprAlloc(size) mprSetAllocName(mprAllocFast(size), MPR_LOC) #define mprMemdup(ptr, size) mprSetAllocName(mprMemdupMem(ptr, size), MPR_LOC) #define mprRealloc(ptr, size) mprSetAllocName(mprReallocMem(ptr, size), MPR_LOC) #define mprAllocZeroed(size) mprSetAllocName(mprAllocMem(size, MPR_ALLOC_ZERO), MPR_LOC) #define mprAllocBlock(size, flags) mprSetAllocName(mprAllocMem(size, flags), MPR_LOC) #define mprAllocObj(type, manage) ((type*) mprSetManager( \ mprSetAllocName(mprAllocMem(sizeof(type), MPR_ALLOC_MANAGER | MPR_ALLOC_ZERO), #type "@" MPR_LOC), (MprManager) manage)) #define mprAllocObjWithFlags(type, manage, flags) ((type*) mprSetManager( \ mprSetAllocName(mprAllocMem(sizeof(type), MPR_ALLOC_MANAGER | MPR_ALLOC_ZERO | flags), #type "@" MPR_LOC), (MprManager) manage)) #define mprAllocStruct(type) ((type*) mprSetAllocName(mprAllocMem(sizeof(type), MPR_ALLOC_ZERO), #type "@" MPR_LOC)) #define mprAllocObjNoZero(type, manage) ((type*) mprSetManager( \ mprSetAllocName(mprAllocMem(sizeof(type), MPR_ALLOC_MANAGER), #type "@" MPR_LOC), (MprManager) manage)) #define mprAllocStructNoZero(type) ((type*) mprSetAllocName(mprAllocFast(sizeof(type)), #type "@" MPR_LOC)) #if DOXYGEN typedef void *Type; /** Allocate a block of memory @description Allocates a block of memory of the required size. The memory is not zeroed. @param size Size of the memory block to allocate. @return Returns a pointer to the allocated block. If memory is not available the memory exhaustion handler specified via mprCreate will be called to allow global recovery. @remarks Do not mix calls to malloc and mprAlloc. @ingroup MprMem @stability Stable. */ PUBLIC void *mprAlloc(size_t size); /** Allocate an object of a given type. @description Allocates a zeroed block of memory large enough to hold an instance of the specified type with a manager callback. This call associates a manager function with an object that will be invoked when the object is freed or the garbage collector needs the object to mark internal properties as being used. This call is implemented as a macro. @param type Type of the object to allocate @param manager Manager function to invoke when the allocation is managed. @return Returns a pointer to the allocated block. If memory is not available the memory exhaustion handler specified via mprCreate will be called to allow global recovery. @remarks Do not mix calls to malloc and mprAlloc. @ingroup MprMem @stability Stable. */ PUBLIC void *mprAllocObj(Type type, MprManager manager) { return 0;} /** Allocate an object of a given type. @description Allocates a zeroed block of memory large enough to hold an instance of the specified type with a manager callback. This call associates a manager function with an object that will be invoked when the object is freed or the garbage collector needs the object to mark internal properties as being used. This call is implemented as a macro. This function can be called by foreign (non Mpr) threads provided you use the MPR_ALLOC_HOLD flag so that the memory will be preserved until you call mprRelease on the memory block. This is important as without the MPR_ALLOC_HOLD flag, the garbage collector could run immediately after calling mprAlloc and collect the memory. When used in an Mpr thread, the garbage collector cannot run unless you call mprYield and so the memory is safe from immediate collection. @param type Type of the object to allocate @param manager Manager function to invoke when the allocation is managed. @param flags Allocation flags. Supported flags include: MPR_ALLOC_MANAGER to reserve room for a manager callback and MPR_ALLOC_ZERO to zero allocated memory. Use MPR_ALLOC_HOLD to return memory immune from GC. Must use this flag if calling from a foreign thread. Use #mprRelease to release back to the system. @return Returns a pointer to the allocated block. If memory is not available the memory exhaustion handler specified via mprCreate will be called to allow global recovery. @remarks Do not mix calls to malloc and mprAlloc. @ingroup MprMem @stability Stable. */ PUBLIC void *mprAllocObjWithFlags(Type type, MprManager manager, int flags) { return 0;} /** Allocate a zeroed block of memory @description Allocates a zeroed block of memory. @param size Size of the memory block to allocate. @return Returns a pointer to the allocated block. If memory is not available the memory exhaustion handler specified via mprCreate will be called to allow global recovery. @remarks Do not mix calls to malloc and mprAlloc. @ingroup MprMem @stability Stable. */ PUBLIC void *mprAllocZeroed(size_t size); #else /* !DOXYGEN */ PUBLIC void *mprAllocMem(size_t size, int flags); PUBLIC void *mprReallocMem(void *ptr, size_t size); PUBLIC void *mprMemdupMem(cvoid *ptr, size_t size); PUBLIC void mprCheckBlock(MprMem *bp); #endif /* Internal APIs */ PUBLIC void mprDestroyMemService(void); PUBLIC void mprStartGCService(void); PUBLIC void mprStopGCService(void); PUBLIC void *mprAllocFast(size_t usize); /******************************** Garbage Coolector ***************************/ /** Add a memory block as a root for garbage collection @description Remove the root when no longer required via #mprAddRoot. @param ptr Any memory pointer @ingroup MprMem @stability Stable. */ PUBLIC void mprAddRoot(cvoid *ptr); /* Flags for mprGC */ #define MPR_CG_DEFAULT 0x0 /**< mprGC flag to run GC if necessary. Will trigger GC and yield. Will block if GC is required. */ #define MPR_GC_FORCE 0x1 /**< mprGC flag to force start a GC sweep whether it is required or not */ #define MPR_GC_NO_BLOCK 0x2 /**< mprGC flag to run GC if ncessary and return without yielding. Will not block. */ #define MPR_GC_COMPLETE 0x4 /**< mprGC flag to force start a GC and wait until the GC cycle fully completes including sweep phase */ /** Collect garbage @description Initiates garbage collection to free unreachable memory blocks. It is normally not required for users to invoke this routine as the garbage collector will be scheduled as required. If the MPR_GC_NO_BLOCK is not specified, this routine yields to the garbage collector by calling #mprYield. Callers must retain all required memory. @param flags Flags to control the collection. Set flags to MPR_GC_FORCE to force a collection. Set to MPR_GC_DEFAULT to perform a conditional sweep where the sweep is only performed if there is sufficient garbage to warrant a collection. Set to MPR_GC_NO_BLOCK to run GC if necessary and return without yielding. Use MPR_GC_COMPLETE to force a GC and wait until the GC cycle fully completes including the sweep phase. @return The number of blocks freed on the last GC sweep. If using MPR_GC_NO_BLOCK, this may be the result from a prior GC sweep. @ingroup MprMem @stability Stable */ PUBLIC int mprGC(int flags); /** Enable or disable the garbage collector @param on Set to one to enable and zero to disable. @return Returns one if the collector was previously enabled. Otherwise returns zero. @ingroup MprMem @stability Stable. */ PUBLIC bool mprEnableGC(bool on); /** Hold a memory block @description This call will protect a memory block from freeing by the garbage collector. Call #mprRelease to allow the block to be collected. @param ptr Any memory block @ingroup MprMem @stability Stable. */ PUBLIC void mprHold(cvoid *ptr); /** Hold memory blocks @description This call will protect a set of memory blocks from freeing by the garbage collector. Call #mprReleaseBlocks to allow the blocks to be collected. @param ptr Any memory block @param ... Other memory blocks. Terminate the list with a NULL. @ingroup MprMem @stability Stable */ PUBLIC void mprHoldBlocks(cvoid *ptr, ...); /** Release a memory block @description This call is used to allow a memory block to be freed by the garbage collector after calling mprHold. You must NEVER use or access the memory block after calling mprRelease. The memory may be freed before the call returns, even when executing in an MPR thread. @param ptr Any memory block @ingroup MprMem @stability Stable. */ PUBLIC void mprRelease(cvoid *ptr); /** Release a memory blocks @description This call is used to allow a memory blocks to be freed by the garbage collector after calling mprHoldBlocks. You must NEVER use or access the memory blocks after calling mprRelease. The memory may be freed before the call returns, even when executing in an MPR thread. @param ptr Any memory block @param ... Other memory blocks. Terminate the list with a NULL. @ingroup MprMem @stability Stable */ PUBLIC void mprReleaseBlocks(cvoid *ptr, ...); /** Remove a memory block as a root for garbage collection @description The memory block should have previously been added as a root via #mprAddRoot. @param ptr Any memory pointer @ingroup MprMem @stability Stable. */ PUBLIC void mprRemoveRoot(cvoid *ptr); #if DOXYGEN /** Mark a memory block as in-use @description To prevent a memory block being freed by the garbage collector, it must be marked as "active". Memory blocks can define a manager that will be invoked by the garbage collector to mark any fields that are required by the original block. @param ptr Reference to managed memory block. This must be managed memory allocated by the MPR. Do not call mprMark on memory allocated via malloc(), strdup() or other non-MPR allocation routines. It is safe pass a NULL pointer to mprMark and this will have no effect. This is a convenient pattern where manager functions can call mprMark() without testing if the element reference is null or not. */ PUBLIC void mprMark(void *ptr); @ingroup MprMem #else #if ME_MPR_ALLOC_STATS #define HINC(field) MPR->heap->stats.field++ #else #define HINC(field) #endif #define mprMark(ptr) \ if (ptr) { \ MprMem *_mp = MPR_GET_MEM((ptr)); \ HINC(markVisited); \ if (_mp->mark != MPR->heap->mark) { \ _mp->mark = MPR->heap->mark; \ if (_mp->hasManager) { \ (GET_MANAGER(_mp))((void*) ptr, MPR_MANAGE_MARK); \ } \ HINC(marked); \ } \ } else {} #endif /* Internal */ PUBLIC int mprCreateGCService(void); PUBLIC void mprWakeGCService(void); PUBLIC void mprResumeThreads(void); PUBLIC int mprSyncThreads(MprTicks timeout); /********************************** Safe Strings ******************************/ /** Safe String Module @description The MPR provides a suite of safe ascii string manipulation routines to help prevent buffer overflows and other potential security traps. @defgroup MprString MprString @see MprString itos itosradix itosbuf mprEprintf mprPrintf scamel scaselesscmp scaselessmatch schr sclone scmp scontains scopy sends sfmt sfmtv shash shashlower sjoin sjoinv slen slower smatch sncaselesscmp snclone sncmp sncopy snumber sfnumber shnumber stitle spbrk srchr srejoin srejoinv sreplace sspn sstarts ssub stemplate stemplateJson stoi stoiradix stok strim supper sncontains mprFprintf fmtv fmt @stability Internal */ typedef struct MprString { void *dummy; } MprString; /** Format a string into a static buffer. @description This call format a string using printf style formatting arguments. A trailing null will always be appended. The call returns the size of the allocated string excluding the null. @param buf Pointer to the buffer. @param maxSize Size of the buffer. @param fmt Printf style format string @param ... Variable arguments to format @return Returns the buffer. @ingroup MprString @stability Stable */ PUBLIC char *fmt(char *buf, ssize maxSize, cchar *fmt, ...) PRINTF_ATTRIBUTE(3,4); /** Format a string into a statically allocated buffer. @description This call format a string using printf style formatting arguments. A trailing null will always be appended. The call returns the size of the allocated string excluding the null. @param buf Pointer to the buffer. @param maxSize Size of the buffer. @param fmt Printf style format string @param args Varargs argument obtained from va_start. @return Returns the buffer; @ingroup MprString @stability Stable */ PUBLIC char *fmtv(char *buf, ssize maxSize, cchar *fmt, va_list args); /** Convert an integer to a string. @description This call converts the supplied 64 bit integer to a string using base 10. @param value Integer value to convert @return An allocated string with the converted number. @ingroup MprString @stability Stable */ PUBLIC char *itos(int64 value); /** Convert an integer to a string. @description This call converts the supplied 64 bit integer to a string according to the specified radix. @param value Integer value to convert @param radix The base radix to use when encoding the number @return An allocated string with the converted number. @ingroup MprString @stability Stable */ PUBLIC char *itosradix(int64 value, int radix); /** Convert an integer to a string buffer. @description This call converts the supplied 64 bit integer into a string formatted into the supplied buffer according to the specified radix. @param buf Pointer to the buffer that will hold the string. @param size Size of the buffer. @param value Integer value to convert @param radix The base radix to use when encoding the number @return Returns a reference to the string. @ingroup MprString @stability Stable */ PUBLIC char *itosbuf(char *buf, ssize size, int64 value, int radix); /** Compare strings ignoring case. This is a safe replacement for strcasecmp. It can handle NULL args. @description Compare two strings ignoring case differences. This call operates similarly to strcmp. @param s1 First string to compare. @param s2 Second string to compare. @return Returns zero if the strings are equivalent, < 0 if s1 sorts lower than s2 in the collating sequence or > 0 if it sorts higher. @ingroup MprString @stability Stable */ PUBLIC int scaselesscmp(cchar *s1, cchar *s2); /** Find a pattern in a string with a caseless comparision @description Locate the first occurrence of pattern in a string. @param str Pointer to the string to search. @param pattern String pattern to search for. @return Returns a reference to the start of the pattern in the string. If not found, returns NULL. @ingroup MprString @stability Evolving */ PUBLIC char *scaselesscontains(cchar *str, cchar *pattern); /** Compare strings ignoring case. This is similar to scaselesscmp but it returns a boolean. @description Compare two strings ignoring case differences. @param s1 First string to compare. @param s2 Second string to compare. @return Returns true if the strings are equivalent, otherwise false. @ingroup MprString @stability Stable */ PUBLIC bool scaselessmatch(cchar *s1, cchar *s2); /** Create a camel case version of the string @description Copy a string into a newly allocated block and make the first character lower case @param str Pointer to the block to duplicate. @return Returns a newly allocated string. @ingroup MprString @stability Stable */ PUBLIC char *scamel(cchar *str); /** Find a character in a string. @description This is a safe replacement for strchr. It can handle NULL args. @param str String to examine @param c Character to search for @return If the character is found, the call returns a reference to the character position in the string. Otherwise, returns NULL. @ingroup MprString @stability Stable */ PUBLIC char *schr(cchar *str, int c); /** Clone a string. @description Copy a string into a newly allocated block. @param str Pointer to the block to duplicate. @return Returns a newly allocated string. @ingroup MprString @stability Stable */ PUBLIC char *sclone(cchar *str); /** Compare strings. @description Compare two strings. This is a safe replacement for strcmp. It can handle null args. @param s1 First string to compare. @param s2 Second string to compare. @return Returns zero if the strings are identical. Return -1 if the first string is less than the second. Return 1 if the first string is greater than the second. @ingroup MprString @stability Stable */ PUBLIC int scmp(cchar *s1, cchar *s2); /** Find a pattern in a string. @description Locate the first occurrence of pattern in a string. @param str Pointer to the string to search. @param pattern String pattern to search for. @return Returns a reference to the start of the pattern in the string. If not found, returns NULL. @ingroup MprString @stability Stable */ PUBLIC char *scontains(cchar *str, cchar *pattern); /** Copy a string. @description Safe replacement for strcpy. Copy a string and ensure the destination buffer is not overflowed. The call returns the length of the resultant string or an error code if it will not fit into the target string. This is similar to strcpy, but it will enforce a maximum size for the copied string and will ensure it is always terminated with a null. @param dest Pointer to a pointer that will hold the address of the allocated block. @param destMax Maximum size of the target string in characters. @param src String to copy @return Returns the number of characters in the target string. @ingroup MprString @stability Stable */ PUBLIC ssize scopy(char *dest, ssize destMax, cchar *src); /** Test if the string ends with a given pattern. @param str String to examine @param suffix Pattern to search for @return Returns a pointer to the start of the pattern if found. Otherwise returns NULL. @ingroup MprString @stability Stable */ PUBLIC cchar *sends(cchar *str, cchar *suffix); /** Erase the contents of a string @param str String to erase @ingroup MprString @stability Stable */ PUBLIC void serase(char *str); /** Format a string. This is a secure verion of printf that can handle null args. @description Format the given arguments according to the printf style format. See mprPrintf for a full list of the format specifies. This is a secure replacement for sprintf, it can handle null arguments without crashes. @param fmt Printf style format string @param ... Variable arguments for the format string @return Returns a newly allocated string @ingroup MprString @stability Stable */ PUBLIC char *sfmt(cchar *fmt, ...) PRINTF_ATTRIBUTE(1,2); /** Format a string. This is a secure verion of printf that can handle null args. @description Format the given arguments according to the printf style format. See mprPrintf for a full list of the format specifies. This is a secure replacement for sprintf, it can handle null arguments without crashes. @param fmt Printf style format string @param args Varargs argument obtained from va_start. @return Returns a newly allocated string @ingroup MprString @stability Stable */ PUBLIC char *sfmtv(cchar *fmt, va_list args); /** Compute a hash code for a string @param str String to examine @param len Length in characters of the string to include in the hash code @return Returns an unsigned integer hash code @ingroup MprString @stability Stable */ PUBLIC uint shash(cchar *str, ssize len); /** Compute a caseless hash code for a string @description This computes a hash code for the string after converting it to lower case. @param str String to examine @param len Length in characters of the string to include in the hash code @return Returns an unsigned integer hash code @ingroup MprString @stability Stable */ PUBLIC uint shashlower(cchar *str, ssize len); /** Catenate strings. @description This catenates strings together with an optional string separator. If the separator is NULL, not separator is used. This call accepts a variable list of strings to append, terminated by a null argument. @param str First string to catentate @param ... Variable number of string arguments to append. Terminate list with NULL. @return Returns an allocated string. @ingroup MprString @stability Stable */ PUBLIC char *sjoin(cchar *str, ...); /** Catenate strings. @description This catenates strings together with an optional string separator. If the separator is NULL, not separator is used. This call accepts a variable list of strings to append, terminated by a null argument. @param str First string to catentate @param args Varargs argument obtained from va_start. @return Returns an allocated string. @ingroup MprString @stability Stable */ PUBLIC char *sjoinv(cchar *str, va_list args); /** Join an array of strings @param argc number of strings to join @param argv Array of strings @param sep Separator string to use. If NULL, then no separator is used. @return A single joined string. @stability Stable @ingroup MprString */ PUBLIC cchar *sjoinArgs(int argc, cchar **argv, cchar *sep); /** Return the length of a string. @description Safe replacement for strlen. This call returns the length of a string and tests if the length is less than a given maximum. It will return zero for NULL args. @param str String to measure. @return Returns the length of the string @ingroup MprString @stability Stable */ PUBLIC ssize slen(cchar *str); /** Convert a string to lower case. @description Convert a string to its lower case equivalent. @param str String to convert. @return An allocated string. @ingroup MprString @stability Stable */ PUBLIC char *slower(cchar *str); /** Compare strings. @description Compare two strings. This is similar to #scmp but it returns a boolean. @param s1 First string to compare. @param s2 Second string to compare. @return Returns true if the strings are equivalent, otherwise false. @ingroup MprString @stability Stable */ PUBLIC bool smatch(cchar *s1, cchar *s2); /** Secure compare strings. @description Compare two strings in constant time. This is similar to #smatch but will not fail fast on first char mismatch. @param s1 First string to compare. @param s2 Second string to compare. @return Returns true if the strings are equivalent, otherwise false. @ingroup MprString @stability Prototype */ PUBLIC bool smatchsec(cchar *s1, cchar *s2); /** Compare strings ignoring case. @description Compare two strings ignoring case differences for a given string length. This call operates similarly to strncasecmp. @param s1 First string to compare. @param s2 Second string to compare. @param len Length of characters to compare. @return Returns zero if the strings are equivalent, < 0 if s1 sorts lower than s2 in the collating sequence or > 0 if it sorts higher. @ingroup MprString @stability Stable */ PUBLIC int sncaselesscmp(cchar *s1, cchar *s2, ssize len); /** Find a pattern in a string with a limit and a caseless comparision @description Locate the first occurrence of pattern in a string, but do not search more than the given character limit. @param str Pointer to the string to search. @param pattern String pattern to search for. @param limit Count of characters in the string to search. @return Returns a reference to the start of the pattern in the string. If not found, returns NULL. @ingroup MprString @stability Stable */ PUBLIC char *sncaselesscontains(cchar *str, cchar *pattern, ssize limit); /** Clone a substring. @description Copy a substring into a newly allocated block. @param str Pointer to the block to duplicate. @param len Number of bytes to copy. The actual length copied is the minimum of the given length and the length of the supplied string. The result is null terminated. @return Returns a newly allocated string. @ingroup MprString @stability Stable */ PUBLIC char *snclone(cchar *str, ssize len); /** Compare strings. @description Compare two strings for a given string length. This call operates similarly to strncmp. @param s1 First string to compare. @param s2 Second string to compare. @param len Length of characters to compare. @return Returns zero if the strings are equivalent, < 0 if s1 sorts lower than s2 in the collating sequence or > 0 if it sorts higher. @ingroup MprString @stability Stable */ PUBLIC int sncmp(cchar *s1, cchar *s2, ssize len); /** Find a pattern in a string with a limit. @description Locate the first occurrence of pattern in a string, but do not search more than the given character limit. @param str Pointer to the string to search. @param pattern String pattern to search for. @param limit Count of characters in the string to search. @return Returns a reference to the start of the pattern in the string. If not found, returns NULL. @ingroup MprString @stability Stable */ PUBLIC char *sncontains(cchar *str, cchar *pattern, ssize limit); /** Copy characters from a string. @description Safe replacement for strncpy. Copy bytes from a string and ensure the target string is not overflowed. The call returns the length of the resultant string or an error code if it will not fit into the target string. This is similar to strcpy, but it will enforce a maximum size for the copied string and will ensure it is terminated with a null. @param dest Pointer to a pointer that will hold the address of the allocated block. @param destMax Maximum size of the target string in characters. @param src String to copy @param len Maximum count of characters to copy @return Returns a reference to the destination if successful or NULL if the string won't fit. @ingroup MprString @stability Stable */ PUBLIC ssize sncopy(char *dest, ssize destMax, cchar *src, ssize len); /* Test if a string is a floating point number @description The supported format is: [+|-][DIGITS][.][DIGITS][(e|E)[+|-]DIGITS] @return true if all characters are digits or '.', 'e', 'E', '+' or '-' @ingroup MprString @stability Stable */ PUBLIC bool sfnumber(cchar *s); /* Test if a string is a hexadecimal number @description The supported format is: [(+|-)][0][(x|X)][HEX_DIGITS] @return true if all characters are digits or 'x' or 'X' @ingroup MprString @stability Stable */ PUBLIC bool shnumber(cchar *s); /* Test if a string is a radix 10 number. @description The supported format is: [(+|-)][DIGITS] @return true if all characters are digits or '+' or '-' @ingroup MprString @stability Stable */ PUBLIC bool snumber(cchar *s); /** Create a Title Case version of the string @description Copy a string into a newly allocated block and make the first character upper case @param str Pointer to the block to duplicate. @return Returns a newly allocated string. @ingroup MprString @stability Stable */ PUBLIC char *stitle(cchar *str); /** Locate the a character from a set in a string. @description This locates in the string the first occurence of any character from a given set of characters. @param str String to examine @param set Set of characters to scan for @return Returns a reference to the first character from the given set. Returns NULL if none found. @ingroup MprString @stability Stable */ PUBLIC char *spbrk(cchar *str, cchar *set); /** Find a character in a string by searching backwards. @description This locates in the string the last occurence of a character. @param str String to examine @param c Character to scan for @return Returns a reference in the string to the requested character. Returns NULL if none found. @ingroup MprString @stability Stable */ PUBLIC char *srchr(cchar *str, int c); /** Append strings to an existing string and reallocate as required. @description Append a list of strings to an existing string. The list of strings is terminated by a null argument. The call returns the size of the allocated block. @param buf Existing (allocated) string to reallocate. May be null. May not be a string literal. @param ... Variable number of string arguments to append. Terminate list with NULL @return Returns an allocated string. @ingroup MprString @stability Stable */ PUBLIC char *srejoin(char *buf, ...); /** Append strings to an existing string and reallocate as required. @description Append a list of strings to an existing string. The list of strings is terminated by a null argument. The call returns the size of the allocated block. @param buf Existing (allocated) string to reallocate. May be null. May not be a string literal. @param args Varargs argument obtained from va_start. @return Returns an allocated string. @ingroup MprString @stability Stable */ PUBLIC char *srejoinv(char *buf, va_list args); /* Replace a pattern in a string @description This will replace all occurrences of the pattern in the string. @param str String to examine @param pattern Pattern to search for. Can be null in which case the str is cloned. @param replacement Replacement pattern. If replacement is null, the pattern is removed. @return A new allocated string @ingroup MprString @stability Stable */ PUBLIC char *sreplace(cchar *str, cchar *pattern, cchar *replacement); /* Test if a string is all white space @return true if all characters are ' ', '\t', '\n', '\r'. True if the string is empty. @ingroup MprString @stability Stable */ PUBLIC bool sspace(cchar *s); /** Split a string at a delimiter @description Split a string and return parts. The string is modified. This routiner never returns null. If there are leading delimiters, the empty string will be returned and *last will be set to the portion after the delimiters. If str is null, a managed reference to the empty string will be returned. If there are no characters after the delimiter, then *last will be set to the empty string. @param str String to tokenize. @param delim Set of characters that are used as token separators. @param last Reference to the portion after the delimiters. Will return an empty string if is not trailing portion. @return Returns a pointer to the first part before the delimiters. If the string begins with delimiters, the empty string will be returned. @ingroup MprString @stability Stable */ PUBLIC char *ssplit(char *str, cchar *delim, char **last); /** Find the end of a spanning prefix @description This scans the given string for characters from the set and returns an index to the first character not in the set. @param str String to examine @param set Set of characters to span @return Returns an index to the first character after the spanning set. If not found, returns the index of the first null. @ingroup MprString @stability Stable */ PUBLIC ssize sspn(cchar *str, cchar *set); /** Test if the string starts with a given pattern. @param str String to examine @param prefix Pattern to search for @return Returns TRUE if the pattern was found. Otherwise returns zero. @ingroup MprString @stability Stable */ PUBLIC bool sstarts(cchar *str, cchar *prefix); /** Replace template tokens in a string with values from a lookup table. Tokens are ${variable} references. @param str String to expand @param tokens Hash table of token values to use @return An expanded string. May return the original string if no "$" references are present. @ingroup MprString @stability Stable @see stemplateJson */ PUBLIC char *stemplate(cchar *str, struct MprHash *tokens); /** Replace template tokens in a string with values from a lookup table. Tokens are ${variable} references. @param str String to expand @param tokens Json object of token values to use @return An expanded string. May return the original string if no "$" references are present. @ingroup MprString @stability Stable @see stemplate */ PUBLIC char *stemplateJson(cchar *str, struct MprJson *tokens); /** Convert a string to a double. @description This call converts the supplied string to a double. @param str Pointer to the string to parse. @return Returns the double equivalent value of the string. @ingroup MprString @stability Stable */ PUBLIC double stof(cchar *str); /** Convert a string to an integer. @description This call converts the supplied string to an integer using base 10. @param str Pointer to the string to parse. @return Returns the integer equivalent value of the string. @ingroup MprString @stability Stable */ PUBLIC int64 stoi(cchar *str); /** Convert a string to an integer. @description This call converts the supplied string to an integer using the specified radix (base). @param str Pointer to the string to parse. @param radix Base to use when parsing the string @param err Return error code. Set to 0 if successful. @return Returns the integer equivalent value of the string. @ingroup MprString */ PUBLIC int64 stoiradix(cchar *str, int radix, int *err); /** Tokenize a string @description Split a string into tokens using a character set as delimiters. @param str String to tokenize. @param delim Set of characters that are used as token separators. @param last Last token pointer. This is a pointer inside the original string. @return Returns a pointer to the next token. The pointer is inside the original string and is not allocated. @ingroup MprString @stability Stable */ PUBLIC char *stok(char *str, cchar *delim, char **last); /** Tokenize a string @description Split a string into tokens using a string pattern as delimiters. @param str String to tokenize. @param pattern String pattern to use for token delimiters. @param last Last token pointer. @return Returns a pointer to the next token. @ingroup MprString @stability Stable */ PUBLIC char *sptok(char *str, cchar *pattern, char **last); /** String to list. This parses the string into space separated arguments. Single and double quotes are supported. @param src Source string to parse @return List of arguments @ingroup MprString @stability Stable */ PUBLIC struct MprList *stolist(cchar *src); /** Create a substring @param str String to examine @param offset Starting offset within str for the beginning of the substring @param length Length of the substring in characters @return Returns a newly allocated substring @ingroup MprString @stability Stable */ PUBLIC char *ssub(cchar *str, ssize offset, ssize length); /* String trim flags */ #define MPR_TRIM_START 0x1 /**< Flag for #strim to trim from the start of the string */ #define MPR_TRIM_END 0x2 /**< Flag for #strim to trim from the end of the string */ #define MPR_TRIM_BOTH 0x3 /**< Flag for #strim to trim from both the start and the end of the string */ /** Trim a string. @description Trim leading and trailing characters off a string. The original string is not modified and the return value is a newly allocated string. @param str String to trim. @param set String of characters to remove. @param where Flags to indicate trim from the start, end or both. Use MPR_TRIM_START, MPR_TRIM_END, MPR_TRIM_BOTH. @return Returns a newly allocated trimmed string. May not equal \a str. @ingroup MprString @stability Stable */ PUBLIC char *strim(cchar *str, cchar *set, int where); /** Convert a string to upper case. @description Convert a string to its upper case equivalent. @param str String to convert. @return Returns a pointer to an allocated string. @ingroup MprString @stability Stable */ PUBLIC char *supper(cchar *str); /************************************ Unicode *********************************/ /* Low-level unicode wide string support. Unicode characters are build-time configurable to be 1, 2 or 4 bytes This API is not yet public */ /* Allocating */ PUBLIC wchar *amtow(cchar *src, ssize *len); PUBLIC char *awtom(wchar *src, ssize *len); #if ME_CHAR_LEN > 1 #define multi(s) awtom(s, 0) #define wide(s) amtow(s, 0) #else #define multi(s) (s) #define wide(s) (s) #endif #if ME_CHAR_LEN > 1 PUBLIC ssize wtom(char *dest, ssize count, wchar *src, ssize len); PUBLIC ssize mtow(wchar *dest, ssize count, cchar *src, ssize len); #if FUTURE PUBLIC wchar *wfmt(wchar *fmt, ...); PUBLIC wchar *itow(wchar *buf, ssize bufCount, int64 value, int radix); PUBLIC wchar *wchr(wchar *s, int c); PUBLIC int wcasecmp(wchar *s1, wchar *s2); PUBLIC wchar *wclone(wchar *str); PUBLIC int wcmp(wchar *s1, wchar *s2); PUBLIC wchar *wcontains(wchar *str, wchar *pattern, ssize limit); PUBLIC ssize wcopy(wchar *dest, ssize destMax, wchar *src); PUBLIC int wends(wchar *str, wchar *suffix); PUBLIC wchar *wfmtv(wchar *fmt, va_list arg); PUBLIC uint whash(wchar *name, ssize len); PUBLIC uint whashlower(wchar *name, ssize len); PUBLIC wchar *wjoin(wchar *sep, ...); PUBLIC wchar *wjoinv(wchar *sep, va_list args); PUBLIC ssize wlen(wchar *s); #endif PUBLIC wchar *wlower(wchar *s); PUBLIC int wncaselesscmp(wchar *s1, wchar *s2, ssize len); PUBLIC int wncmp(wchar *s1, wchar *s2, ssize len); PUBLIC ssize wncopy(wchar *dest, ssize destCount, wchar *src, ssize len); PUBLIC wchar *wpbrk(wchar *str, wchar *set); PUBLIC wchar *wrchr(wchar *s, int c); PUBLIC wchar *wrejoin(wchar *buf, wchar *sep, ...); PUBLIC wchar *wrejoinv(wchar *buf, wchar *sep, va_list args); PUBLIC ssize wspn(wchar *str, wchar *set); PUBLIC int wstarts(wchar *str, wchar *prefix); PUBLIC wchar *wsub(wchar *str, ssize offset, ssize len); PUBLIC int64 wtoi(wchar *str); PUBLIC int64 wtoiradix(wchar *str, int radix, int *err); PUBLIC wchar *wtok(wchar *str, wchar *delim, wchar **last); PUBLIC wchar *wtrim(wchar *str, wchar *set, int where); PUBLIC wchar *wupper(wchar *s); #else /* CHAR_LEN == 1 */ #define wtom(dest, count, src, len) sncopy(dest, count, src, len) #define mtow(dest, count, src, len) sncopy(dest, count, src, len) #define itowbuf(buf, bufCount, value, radix) itosbuf(buf, bufCount, value, radix) #define wchr(str, c) schr(str, c) #define wclone(str) sclone(str) #define wcasecmp(s1, s2) scaselesscmp(s1, s2) #define wcmp(s1, s2) scmp(s1, s2) #define wcontains(str, pattern) scontains(str, pattern) #define wncontains(str, pattern, limit) sncontains(str, pattern, limit) #define wcopy(dest, count, src) scopy(dest, count, src) #define wends(str, suffix) sends(str, suffix) #define wfmt sfmt #define wfmtv(fmt, arg) sfmtv(fmt, arg) #define whash(name, len) shash(name, len) #define whashlower(name, len) shashlower(name, len) #define wjoin sjoin #define wjoinv(sep, args) sjoinv(sep, args) #define wlen(str) slen(str) #define wlower(str) slower(str) #define wncmp(s1, s2, len) sncmp(s1, s2, len) #define wncaselesscmp(s1, s2, len) sncaselesscmp(s1, s2, len) #define wncopy(dest, count, src, len) sncopy(dest, count, src, len) #define wpbrk(str, set) spbrk(str, set) #define wrchr(str, c) srchr(str, c) #define wrejoin srejoin #define wrejoinv(buf, sep, args) srejoinv(buf, sep, args) #define wspn(str, set) sspn(str, set) #define wstarts(str, prefix) sstarts(str, prefix) #define wsub(str, offset, len) ssub(str, offset, len) #define wtoi(str) stoi(str) #define wtoiradix(str, radix, err) stoiradix(str, radix, err) #define wtok(str, delim, last) stok(str, delim, last) #define wtrim(str, set, where) strim(str, set, where) #define wupper(str) supper(str) #endif /* ME_CHAR_LEN > 1 */ /********************************* Mixed Strings ******************************/ /* These routines operate on wide strings mixed with a multibyte/ascii operand This API is not yet public */ #if ME_CHAR_LEN > 1 #if FUTURE PUBLIC int mcaselesscmp(wchar *s1, cchar *s2); PUBLIC int mcmp(wchar *s1, cchar *s2); PUBLIC wchar *mcontains(wchar *str, cchar *pattern); PUBLIC wchar *mncontains(wchar *str, cchar *pattern, ssize limit); PUBLIC ssize mcopy(wchar *dest, ssize destMax, cchar *src); PUBLIC int mends(wchar *str, cchar *suffix); PUBLIC wchar *mfmt(cchar *fmt, ...); PUBLIC wchar *mfmtv(cchar *fmt, va_list arg); PUBLIC wchar *mjoin(cchar *str, ...); PUBLIC wchar *mjoinv(wchar *buf, va_list args); PUBLIC int mncmp(wchar *s1, cchar *s2, ssize len); PUBLIC int mncaselesscmp(wchar *s1, cchar *s2, ssize len); PUBLIC ssize mncopy(wchar *dest, ssize destMax, cchar *src, ssize len); PUBLIC wchar *mpbrk(wchar *str, cchar *set); PUBLIC wchar *mrejoin(wchar *buf, cchar *sep, ...); PUBLIC wchar *mrejoinv(wchar *buf, cchar *sep, va_list args); PUBLIC ssize mspn(wchar *str, cchar *set); PUBLIC int mstarts(wchar *str, cchar *prefix); PUBLIC wchar *mtok(wchar *str, cchar *delim, wchar **last); PUBLIC wchar *mtrim(wchar *str, cchar *set, int where); #endif #else /* ME_CHAR_LEN <= 1 */ #define mcaselesscmp(s1, s2) scaselesscmp(s1, s2) #define mcmp(s1, s2) scmp(s1, s2) #define mcontains(str, pattern) scontains(str, pattern) #define mncontains(str, pattern, limit) sncontains(str, pattern, limit) #define mcopy(dest, count, src) scopy(dest, count, src) #define mends(str, suffix) sends(str, suffix) #define mfmt sfmt #define mfmtv(fmt, arg) sfmtv(fmt, arg) #define mjoin sjoin #define mjoinv(sep, args) sjoinv(sep, args) #define mncmp(s1, s2, len) sncmp(s1, s2, len) #define mncaselesscmp(s1, s2, len) sncaselesscmp(s1, s2, len) #define mncopy(dest, count, src, len) sncopy(dest, count, src, len) #define mpbrk(str, set) spbrk(str, set) #define mrejoin srejoin #define mrejoinv(buf, sep, args) srejoinv(buf, sep, args) #define mspn(str, set) sspn(str, set) #define mstarts(str, prefix) sstarts(str, prefix) #define mtok(str, delim, last) stok(str, delim, last) #define mtrim(str, set, where) strim(str, set, where) #endif /* ME_CHAR_LEN <= 1 */ /************************************ Formatting ******************************/ /** Print a formatted message to the standard error channel @description This is a secure replacement for fprintf(stderr). @param fmt Printf style format string @param ... Variable arguments to format @return Returns the number of bytes written @ingroup MprString @stability Stable */ PUBLIC ssize mprEprintf(cchar *fmt, ...) PRINTF_ATTRIBUTE(1,2); /** Print a formatted message to a file descriptor @description This is a replacement for fprintf as part of the safe string MPR library. It minimizes memory use and uses a file descriptor instead of a File pointer. @param file MprFile object returned via #mprOpenFile. @param fmt Printf style format string @param ... Variable arguments to format @return Returns the number of bytes written @ingroup MprString @stability Stable */ PUBLIC ssize mprFprintf(struct MprFile *file, cchar *fmt, ...) PRINTF_ATTRIBUTE(2,3); /** Formatted print. This is a secure verion of printf that can handle null args. @description This is a secure replacement for printf. It can handle null arguments without crashes. @param fmt Printf style format string @param ... Variable arguments to format @return Returns the number of bytes written @ingroup MprString @stability Stable */ PUBLIC ssize mprPrintf(cchar *fmt, ...) PRINTF_ATTRIBUTE(1, 2); /** Print to stdout and add a trailing newline @internal */ PUBLIC ssize print(cchar *fmt, ...) PRINTF_ATTRIBUTE(1,2); /** Format a string into a buffer. @description This routine will format the arguments into a result. If a buffer is supplied, it will be used. Otherwise if the buf argument is NULL, a buffer will be allocated. The arguments will be formatted up to the maximum size supplied by the maxsize argument. A trailing null will always be appended. @param buf Optional buffer to contain the formatted result @param maxsize Maximum size of the result @param fmt Printf style format string @param args Variable arguments to format @return Returns the number of characters in the string. @ingroup MprString @internal @stability Stable */ PUBLIC char *mprPrintfCore(char *buf, ssize maxsize, cchar *fmt, va_list args); /********************************* Floating Point *****************************/ #if ME_FLOAT /** Floating Point Services @stability Stable @see mprDota mprIsInfinite mprIsNan mprIsZero @defgroup MprFloat MprFloat @stability Internal */ typedef struct MprFloat { int dummy; } MprFloat; /** Test if a double value is infinte @param value Value to test @return True if the value is +Infinity or -Infinity @ingroup MprFloat @stability Stable */ PUBLIC int mprIsInfinite(double value); /** Test if a double value is zero @param value Value to test @return True if the value is zero @ingroup MprFloat @stability Stable */ PUBLIC int mprIsZero(double value); /** Test if a double value is not-a-number @param value Value to test @return True if the value is NaN @ingroup MprFloat @stability Stable */ PUBLIC int mprIsNan(double value); #endif /* ME_FLOAT */ /********************************* Buffering **********************************/ /** Buffer refill callback function @description Function to call when the buffer is depleted and needs more data. @param buf Instance of an MprBuf @param arg Data argument supplied to #mprSetBufRefillProc @returns The callback should return 0 if successful, otherwise a negative error code. @ingroup MprBuf @stability Stable */ typedef int (*MprBufProc)(struct MprBuf* bp, void *arg); /** Dynamic Buffer Module @description MprBuf is a flexible, dynamic growable buffer structure. It has start and end pointers to the data buffer which act as read/write pointers. Routines are provided to get and put data into and out of the buffer and automatically advance the appropriate start/end pointer. By definition, the buffer is empty when the start pointer == the end pointer. Buffers can be created with a fixed size or can grow dynamically as more data is added to the buffer. \n\n For performance, the specification of MprBuf is deliberately exposed. All members of MprBuf are implicitly public. However, it is still recommended that wherever possible, you use the accessor routines provided. @see MprBuf MprBufProc mprAddNullToBuf mprAddNullToWideBuf mprAdjustBufEnd mprAdjustBufStart mprBufToString mprCloneBuf mprCompactBuf mprCreateBuf mprFlushBuf mprGetBlockFromBuf mprGetBufEnd mprGetBufLength mprGetBufOrigin mprGetBufRefillProc mprGetBufSize mprGetBufSpace mprGetBufStart mprGetCharFromBuf mprGrowBuf mprInsertCharToBuf mprLookAtLastCharInBuf mprLookAtNextCharInBuf mprPutBlockToBuf mprPutCharToBuf mprPutCharToWideBuf mprPutToBuf mprPutFmtToWideBuf mprPutIntToBuf mprPutPadToBuf mprPutStringToBuf mprPutStringToWideBuf mprPutSubStringToBuf mprRefillBuf mprResetBufIfEmpty mprSetBufMax mprSetBufRefillProc mprSetBufSize @defgroup MprBuf MprBuf @stability Internal. */ typedef struct MprBuf { char *data; /**< Actual buffer for data */ char *endbuf; /**< Pointer one past the end of buffer */ char *start; /**< Pointer to next data char */ char *end; /**< Pointer one past the last data chr */ ssize buflen; /**< Current size of buffer */ ssize maxsize; /**< Max size the buffer can ever grow */ ssize growBy; /**< Next growth increment to use */ MprBufProc refillProc; /**< Auto-refill procedure */ void *refillArg; /**< Refill arg - must be alloced memory */ } MprBuf; /** Add a null character to the buffer contents. @description Add a null byte but do not change the buffer content lengths. The null is added outside the "official" content length. This is useful when calling #mprGetBufStart and using the returned pointer as a "C" string pointer. @param buf Buffer created via mprCreateBuf @ingroup MprBuf @stability Stable. */ PUBLIC void mprAddNullToBuf(MprBuf *buf); /** Adjust the buffer end position @description Adjust the buffer end position by the specified amount. This is typically used to advance the end position as content is appended to the buffer. Adjusting the start or end position will change the value returned by #mprGetBufLength. If using the mprPutBlock or mprPutChar routines, adjusting the end position is done automatically. @param buf Buffer created via mprCreateBuf @param count Positive or negative count of bytes to adjust the end position. @ingroup MprBuf @stability Stable. */ PUBLIC void mprAdjustBufEnd(MprBuf *buf, ssize count); /** Adjust the buffer start position @description Adjust the buffer start position by the specified amount. This is typically used to advance the start position as content is consumed. Adjusting the start or end position will change the value returned by #mprGetBufLength. If using the mprGetBlock or mprGetChar routines, adjusting the start position is done automatically. @param buf Buffer created via mprCreateBuf @param count Positive or negative count of bytes to adjust the start position. @ingroup MprBuf @stability Stable. */ PUBLIC void mprAdjustBufStart(MprBuf *buf, ssize count); /** Convert the buffer contents to a string @param buf Buffer created via mprCreateBuf @returns Allocated string @ingroup MprBuf @stability Stable. */ PUBLIC char *mprBufToString(MprBuf *buf); /** Create a new buffer @description Create a new buffer. @param initialSize Initial size of the buffer @param maxSize Maximum size the buffer can grow to @return a new buffer @ingroup MprBuf @stability Stable. */ PUBLIC MprBuf *mprCreateBuf(ssize initialSize, ssize maxSize); /** Clone a buffer @description Copy the buffer and contents into a newly allocated buffer @param orig Original buffer to copy @return Returns a newly allocated buffer @stability Stable. */ PUBLIC MprBuf *mprCloneBuf(MprBuf *orig); /** Clone a buffer contents @param bp Buffer to copy @return Returns a newly allocated memory block containing the buffer contents. @stability Stable. */ PUBLIC char *mprCloneBufMem(MprBuf *bp); /** Clone a buffer contents @param bp Buffer to copy @return Returns a string containing the buffer contents. @stability Stable. */ PUBLIC char *mprCloneBufAsString(MprBuf *bp); /** Compact the buffer contents @description Compact the buffer contents by copying the contents down to start the the buffer origin. @param buf Buffer created via mprCreateBuf @ingroup MprBuf @stability Stable. */ PUBLIC void mprCompactBuf(MprBuf *buf); /** Flush the buffer contents @description Discard the buffer contents and reset the start end content pointers. @param buf Buffer created via mprCreateBuf @ingroup MprBuf @stability Stable. */ PUBLIC void mprFlushBuf(MprBuf *buf); /** Get a block of data from the buffer @description Get a block of data from the buffer start and advance the start position. If the requested length is greater than the available buffer content, then return whatever data is available. @param buf Buffer created via mprCreateBuf @param blk Destination block for the read data. @param count Count of bytes to read from the buffer. @return The count of bytes read into the block or -1 if the buffer is empty. @ingroup MprBuf @stability Stable. */ PUBLIC ssize mprGetBlockFromBuf(MprBuf *buf, char *blk, ssize count); /** Get a reference to the end of the buffer contents @description Get a pointer to the location immediately after the end of the buffer contents. @param buf Buffer created via mprCreateBuf @returns Pointer to the end of the buffer data contents. Points to the location one after the last data byte. @ingroup MprBuf @stability Stable. */ PUBLIC char *mprGetBufEnd(MprBuf *buf); /** Get the buffer content length. @description Get the length of the buffer contents. This is not the same as the buffer size which may be larger. @param buf Buffer created via mprCreateBuf @returns The length of the content stored in the buffer in bytes @ingroup MprBuf @stability Stable. */ PUBLIC ssize mprGetBufLength(MprBuf *buf); /** Get the buffer refill procedure @description Return the buffer refill callback function. @param buf Buffer created via mprCreateBuf @returns The refill call back function if defined. @ingroup MprBuf @stability Stable. */ PUBLIC MprBufProc mprGetBufRefillProc(MprBuf *buf); /** Get the origin of the buffer content storage. @description Get a pointer to the start of the buffer content storage. This is always and allocated block. @param buf Buffer created via mprCreateBuf @returns A pointer to the buffer content storage. @ingroup MprBuf @stability Stable. */ PUBLIC char *mprGetBuf(MprBuf *buf); /** Get the current size of the buffer content storage. @description This returns the size of the memory block allocated for storing the buffer contents. @param buf Buffer created via mprCreateBuf @returns The size of the buffer content storage. @ingroup MprBuf @stability Stable. */ PUBLIC ssize mprGetBufSize(MprBuf *buf); /** Get the space available to store content @description Get the number of bytes available to store content in the buffer @param buf Buffer created via mprCreateBuf @returns The number of bytes available @ingroup MprBuf @stability Stable. */ PUBLIC ssize mprGetBufSpace(MprBuf *buf); /** Get the start of the buffer contents @description Get a pointer to the start of the buffer contents. Use #mprGetBufLength to determine the length of the content. Use #mprGetBufEnd to get a pointer to the location after the end of the content. @param buf Buffer created via mprCreateBuf @returns Pointer to the start of the buffer data contents @ingroup MprBuf @stability Stable. */ PUBLIC char *mprGetBufStart(MprBuf *buf); /** Get a character from the buffer @description Get the next byte from the buffer start and advance the start position. @param buf Buffer created via mprCreateBuf @return The character or -1 if the buffer is empty. @ingroup MprBuf @stability Stable. */ PUBLIC int mprGetCharFromBuf(MprBuf *buf); /** Grow the buffer @description Grow the storage allocated for content for the buffer. The new size must be less than the maximum limit specified via #mprCreateBuf or #mprSetBufSize. @param buf Buffer created via mprCreateBuf @param count Count of bytes by which to grow the buffer content size. @returns Zero if successful and otherwise a negative error code @ingroup MprBuf @stability Stable. */ PUBLIC int mprGrowBuf(MprBuf *buf, ssize count); /** Insert a character into the buffer @description Insert a character into to the buffer prior to the current buffer start point. @param buf Buffer created via mprCreateBuf @param c Character to append. @returns Zero if successful and otherwise a negative error code @ingroup MprBuf @stability Stable. */ PUBLIC int mprInsertCharToBuf(MprBuf *buf, int c); /** Peek at the next character in the buffer @description Non-destructively return the next character from the start position in the buffer. The character is returned and the start position is not altered. @param buf Buffer created via mprCreateBuf @returns Zero if successful and otherwise a negative error code @ingroup MprBuf @stability Stable. */ PUBLIC int mprLookAtNextCharInBuf(MprBuf *buf); /** Peek at the last character in the buffer @description Non-destructively return the last character from just prior to the end position in the buffer. The character is returned and the end position is not altered. @param buf Buffer created via mprCreateBuf @returns Zero if successful and otherwise a negative error code @ingroup MprBuf @stability Stable. */ PUBLIC int mprLookAtLastCharInBuf(MprBuf *buf); /** Put a block to the buffer. @description Append a block of data to the buffer at the end position and increment the end pointer. @param buf Buffer created via mprCreateBuf @param ptr Block to append @param size Size of block to append @returns Zero if successful and otherwise a negative error code @ingroup MprBuf @stability Stable. */ PUBLIC ssize mprPutBlockToBuf(MprBuf *buf, cchar *ptr, ssize size); /** Put a character to the buffer. @description Append a character to the buffer at the end position and increment the end pointer. @param buf Buffer created via mprCreateBuf @param c Character to append @returns Zero if successful and otherwise a negative error code @ingroup MprBuf @stability Stable. */ PUBLIC int mprPutCharToBuf(MprBuf *buf, int c); /** Put a formatted string to the buffer. @description Format a string and append to the buffer at the end position and increment the end pointer. @param buf Buffer created via mprCreateBuf @param fmt Printf style format string @param ... Variable arguments for the format string @returns Zero if successful and otherwise a negative error code @ingroup MprBuf @stability Stable. */ PUBLIC ssize mprPutToBuf(MprBuf *buf, cchar *fmt, ...) PRINTF_ATTRIBUTE(2,3); /** Put an integer to the buffer. @description Append a integer to the buffer at the end position and increment the end pointer. @param buf Buffer created via mprCreateBuf @param i Integer to append to the buffer @returns Number of characters added to the buffer, otherwise a negative error code @ingroup MprBuf @stability Stable. */ PUBLIC ssize mprPutIntToBuf(MprBuf *buf, int64 i); /** Put padding characters to the buffer. @description Append padding characters to the buffer at the end position and increment the end pointer. @param buf Buffer created via mprCreateBuf @param c Character to append @param count Count of pad characters to put @returns Zero if successful and otherwise a negative error code @ingroup MprBuf @stability Stable */ PUBLIC ssize mprPutPadToBuf(MprBuf *buf, int c, ssize count); /** Put a string to the buffer. @description Append a null terminated string to the buffer at the end position and increment the end pointer. @param buf Buffer created via mprCreateBuf @param str String to append @returns Zero if successful and otherwise a negative error code @ingroup MprBuf @stability Stable. */ PUBLIC ssize mprPutStringToBuf(MprBuf *buf, cchar *str); /** Put a substring to the buffer. @description Append a null terminated substring to the buffer at the end position and increment the end pointer. @param buf Buffer created via mprCreateBuf @param str String to append @param count Put at most count characters to the buffer @returns Zero if successful and otherwise a negative error code @ingroup MprBuf @stability Stable. */ PUBLIC ssize mprPutSubStringToBuf(MprBuf *buf, cchar *str, ssize count); /** Refill the buffer with data @description Refill the buffer by calling the refill procedure specified via #mprSetBufRefillProc @param buf Buffer created via mprCreateBuf @returns Zero if successful and otherwise a negative error code @ingroup MprBuf @stability Stable. */ PUBLIC int mprRefillBuf(MprBuf *buf); /** Reset the buffer @description If the buffer is empty, reset the buffer start and end pointers to the beginning of the buffer. @param buf Buffer created via mprCreateBuf @ingroup MprBuf @stability Stable. */ PUBLIC void mprResetBufIfEmpty(MprBuf *buf); /** Set the maximum buffer size @description Update the maximum buffer size set when the buffer was created @param buf Buffer created via mprCreateBuf @param maxSize New maximum size the buffer can grow to @ingroup MprBuf @stability Stable. */ PUBLIC void mprSetBufMax(MprBuf *buf, ssize maxSize); /** Set the buffer refill procedure @description Define a buffer refill procedure. The MprBuf module will not invoke or manage this refill procedure. It is simply stored to allow upper layers to use and provide their own auto-refill mechanism. @param buf Buffer created via mprCreateBuf @param fn Callback function to store. @param arg Callback data argument. @ingroup MprBuf @stability Stable. */ PUBLIC void mprSetBufRefillProc(MprBuf *buf, MprBufProc fn, void *arg); /** Set the buffer size @description Set the current buffer content size and maximum size limit. Setting a current size will immediately grow the buffer to be this size. If the size is less than the current buffer size, the requested size will be ignored. ie. this call will not shrink the buffer. Setting a maxSize will define a maximum limit for how big the buffer contents can grow. Set either argument to -1 to be ignored. @param buf Buffer created via mprCreateBuf @param size Size to immediately make the buffer. If size is less than the current buffer size, it will be ignored. Set to -1 to ignore this parameter. @param maxSize Maximum size the buffer contents can grow to. @returns Zero if successful and otherwise a negative error code @ingroup MprBuf @stability Stable. */ PUBLIC int mprSetBufSize(MprBuf *buf, ssize size, ssize maxSize); #if DOXYGEN || ME_CHAR_LEN > 1 #if FUTURE /** Add a wide null character to the buffer contents. @description Add a null character but do not change the buffer content lengths. The null is added outside the "official" content length. This is useful when calling #mprGetBufStart and using the returned pointer as a string pointer. @param buf Buffer created via mprCreateBuf @ingroup MprBuf @stability Evolving */ PUBLIC void mprAddNullToWideBuf(MprBuf *buf); /** Put a wide character to the buffer. @description Append a wide character to the buffer at the end position and increment the end pointer. @param buf Buffer created via mprCreateBuf @param c Character to append @returns Zero if successful and otherwise a negative error code @ingroup MprBuf @stability Prototype */ PUBLIC int mprPutCharToWideBuf(MprBuf *buf, int c); /** Put a wide string to the buffer. @description Append a null terminated wide string to the buffer at the end position and increment the end pointer. @param buf Buffer created via mprCreateBuf @param str String to append @returns Count of bytes written and otherwise a negative error code @ingroup MprBuf @stability Prototype */ PUBLIC ssize mprPutStringToWideBuf(MprBuf *buf, cchar *str); /** Put a formatted wide string to the buffer. @description Format a string and append to the buffer at the end position and increment the end pointer. @param buf Buffer created via mprCreateBuf @param fmt Printf style format string @param ... Variable arguments for the format string @returns Count of bytes written and otherwise a negative error code @ingroup MprBuf @stability Prototype */ PUBLIC ssize mprPutFmtToWideBuf(MprBuf *buf, cchar *fmt, ...) PRINTF_ATTRIBUTE(2,3); #endif /* FUTURE */ #else /* ME_CHAR_LEN == 1 */ #define mprAddNullToWideBuf mprAddNullToBuf #define mprPutCharToWideBuf mprPutCharToBuf #define mprPutStringToWideBuf mprPutStringToBuf #define mprPutFmtToWideBuf mprPutToBuf #endif /* Macros for speed */ #define mprGetBufLength(bp) ((bp) ? ((ssize) ((bp)->end - (bp)->start)) : 0) #define mprGetBufSize(bp) ((bp)->buflen) #define mprGetBufSpace(bp) ((bp)->endbuf - (bp)->end) #define mprGetBuf(bp) ((bp)->data) #define mprGetBufStart(bp) ((bp)->start) #define mprGetBufEnd(bp) ((bp)->end) /* Prototype */ PUBLIC uint mprGetUint16FromBuf(MprBuf *buf); PUBLIC uint mprGetUint24FromBuf(MprBuf *buf); PUBLIC uint mprGetUint32FromBuf(MprBuf *buf); PUBLIC uint mprPeekUint32FromBuf(MprBuf *buf); PUBLIC void mprPutUint16ToBuf(MprBuf *buf, uint16 num); PUBLIC void mprPutUint32ToBuf(MprBuf *buf, uint32 num); /******************************** Date and Time *******************************/ /** Format a date according to RFC822: (Fri, 07 Jan 2003 12:12:21 PDT) */ #define MPR_RFC_DATE "%a, %d %b %Y %T %Z" #define MPR_RFC822_DATE "%a, %d %b %Y %T %Z" /* ISO dates. 2009-05-21T16:06:05.000Z */ #define MPR_ISO_DATE "%Y-%m-%dT%H:%M:%S.%fZ" /** Default date format used in mprFormatLocalTime/mprFormatUniversalTime when no format supplied */ #define MPR_DEFAULT_DATE "%a %b %d %T %Y %Z" /** Date format for use in HTTP (headers) */ #define MPR_HTTP_DATE "%a, %d %b %Y %T GMT" /** Date format for RFC 3399 for use in HTML 5 */ #define MPR_RFC3399_DATE "%FT%TZ" /** Date for use in log files (compact) */ #define MPR_LOG_DATE "%D %T" /********************************** Defines ***********************************/ /** Date and Time Service @stability Stable @see MprTime mprCompareTime mprCreateTimeService mprDecodeLocalTime mprDecodeUniversalTime mprFormatLocalTime mprFormatTm mprGetDate mprGetElapsedTicks mprGetRemainingTicks mprGetHiResTicks mprGetTimeZoneOffset mprMakeTime mprMakeUniversalTime mprParseTime @defgroup MprTime MprTime */ typedef Time MprTime; /** Mpr time structure. @description MprTime is the cross platform time abstraction structure. Time is stored as milliseconds since the epoch: 00:00:00 UTC Jan 1 1970. MprTime is typically a 64 bit quantity. @ingroup MprTime @stability Internal */ PUBLIC int mprCreateTimeService(void); /** Compare two times @description compare two times and return a code indicating which is greater, less or equal @param t1 First time @param t2 Second time @returns Zero if equal, -1 if t1 is less than t2 otherwise one. @ingroup MprTime @stability Stable */ PUBLIC int mprCompareTime(MprTime t1, MprTime t2); /** Decode a time value into a tokenized local time value. @description Safe replacement for localtime. This call converts the time value to local time and formats the as a struct tm. @param timep Pointer to a tm structure to hold the result @param time Time to format @ingroup MprTime @stability Stable */ PUBLIC void mprDecodeLocalTime(struct tm *timep, MprTime time); /** Decode a time value into a tokenized UTC time structure. @description Safe replacement for gmtime. This call converts the supplied time value to UTC time and parses the result into a tm structure. @param timep Pointer to a tm structure to hold the result. @param time The time to format @ingroup MprTime @stability Stable */ PUBLIC void mprDecodeUniversalTime(struct tm *timep, MprTime time); /** Convert a time value to local time and format as a string. @description Safe replacement for ctime. @param fmt Time format string. See #mprFormatUniversalTime for time formats. @param time Time to format. Use mprGetTime to retrieve the current time. @return The formatting time string @ingroup MprTime @stability Stable */ PUBLIC char *mprFormatLocalTime(cchar *fmt, MprTime time); /** Convert a time value to universal time and format as a string. @description Format a time string. This uses strftime if available and so the supported formats vary from platform to platform. Strftime should supports some of these these formats described below. @param time Time to format. Use mprGetTime to retrieve the current time. @param fmt Time format string \n %A ... full weekday name (Monday) \n %a ... abbreviated weekday name (Mon) \n %B ... full month name (January) \n %b ... abbreviated month name (Jan) \n %C ... century. Year / 100. (0-N) \n %c ... standard date and time representation \n %D ... date (%m/%d/%y) \n %d ... day-of-month (01-31) \n %e ... day-of-month with a leading space if only one digit ( 1-31) \n %f ... milliseconds \n %F ... same as %Y-%m-%d \n %H ... hour (24 hour clock) (00-23) \n %h ... same as %b \n %I ... hour (12 hour clock) (01-12) \n %j ... day-of-year (001-366) \n %k ... hour (24 hour clock) (0-23) \n %l ... the hour (12-hour clock) as a decimal number (1-12); single digits are preceded by a blank. \n %M ... minute (00-59) \n %m ... month (01-12) \n %n ... a newline \n %P ... lower case am / pm \n %p ... AM / PM \n %R ... same as %H:%M \n %r ... same as %H:%M:%S %p \n %S ... second (00-59) \n %s ... seconds since epoch \n %T ... time (%H:%M:%S) \n %t ... a tab. \n %U ... week-of-year, first day sunday (00-53) \n %u ... the weekday (Monday as the first day of the week) as a decimal number (1-7). \n %v ... is equivalent to ``%e-%b-%Y''. \n %W ... week-of-year, first day monday (00-53) \n %w ... weekday (0-6, sunday is 0) \n %X ... standard time representation \n %x ... standard date representation \n %Y ... year with century \n %y ... year without century (00-99) \n %Z ... timezone name \n %z ... offset from UTC (-hhmm or +hhmm) \n %+ ... national representation of the date and time (the format is similar to that produced by date(1)). \n %% ... percent sign \n\n Some platforms may also support the following format extensions: \n %E* ... POSIX locale extensions. Where "*" is one of the characters: c, C, x, X, y, Y. \n %G ... a year as a decimal number with century. This year is the one that contains the greater part of the week (Monday as the first day of the week). \n %g ... the same year as in ``%G'', but as a decimal number without century (00-99). \n %O* ... POSIX locale extensions. Where "*" is one of the characters: d, e, H, I, m, M, S, u, U, V, w, W, y. Additionly %OB implemented to represent alternative months names (used standalone, without day mentioned). \n %V ... the week number of the year (Monday as the first day of the week) as a decimal number (01-53). If the week containing January 1 has four or more days in the new year, then it is week 1; otherwise it is the last week of the previous year, and the next week is week 1. \n\n Useful formats: \n RFC822: "%a, %d %b %Y %H:%M:%S %Z "Fri, 07 Jan 2003 12:12:21 PDT" \n "%T %F "12:12:21 2007-01-03" \n "%v "07-Jul-2003" \n RFC3399: "%FT%TZ" "1985-04-12T23:20:50.52Z" which is April 12 1985, 23:20.50 and 52 msec @return The formatting time string @ingroup MprTime @stability Stable */ PUBLIC char *mprFormatUniversalTime(cchar *fmt, MprTime time); /** Format a time value as a local time. @description This call formats the time value supplied via \a timep. @param fmt The time format to use. See #mprFormatUniversalTime for time formats. @param timep The time value to format. @return The formatting time string. @ingroup MprTime @stability Stable */ PUBLIC char *mprFormatTm(cchar *fmt, struct tm *timep); /** Get the system time. @description Get the system time in milliseconds. This is a monotonically increasing time counter. It does not represent wall-clock time. @return Returns the system time in milliseconds. @ingroup MprTime @stability Stable */ PUBLIC MprTicks mprGetTicks(void); /** Get the time. @description Get the date/time in milliseconds since Jan 1 1970. @return Returns the time in milliseconds since Jan 1 1970. @ingroup MprTime @stability Stable */ PUBLIC MprTime mprGetTime(void); /** Get a string representation of the current date/time @description Get the current date/time as a string according to the given format. @param fmt Date formatting string. See strftime for acceptable date format specifiers. If null, then this routine uses the #MPR_DEFAULT_DATE format. @return An allocated date string @ingroup MprTime @stability Stable */ PUBLIC char *mprGetDate(char *fmt); /** Get the CPU tick count. @description Get the current CPU tick count. This is a system dependant high resolution timer. On some systems, this returns time in nanosecond resolution. @return Returns the CPU time in ticks. Will return the system time if CPU ticks are not available. @ingroup MprTicks @stability Internal */ PUBLIC uint64 mprGetHiResTicks(void); #if (LINUX || MACOSX || WINDOWS) && (ME_CPU_ARCH == ME_CPU_X86 || ME_CPU_ARCH == ME_CPU_X64) #define MPR_HIGH_RES_TIMER 1 #else #define MPR_HIGH_RES_TIMER 0 #endif #if ME_MPR_DEBUG_LOGGING #if MPR_HIGH_RES_TIMER #define MPR_MEASURE(level, tag1, tag2, op) \ if ((level) <= MPR->logLevel) { \ MprTicks elapsed, start = mprGetTicks(); \ uint64 ticks = mprGetHiResTicks(); \ op; \ elapsed = mprGetTicks() - start; \ if (elapsed < 1000) { \ mprLog("mpr time", level, "%s.%s elapsed %'lld msec, %'lld ticks", \ tag1, tag2, elapsed, mprGetHiResTicks() - ticks); \ } else { \ mprLog("mpr time", level, "%s.%s elapsed %'lld msec", tag1, tag2, elapsed); \ } \ } else { \ op; \ } #else #define MPR_MEASURE(level, tag1, tag2, op) \ if ((level) <= MPR->logLevel) { \ MprTicks start = mprGetTicks(); \ op; \ mprLog("mpr time", level, "%s.%s elapsed %'lld msec", tag1, tag2, mprGetTicks() - start); \ } else { \ op; \ } #endif #else #define MPR_MEASURE(level, tag1, tag2, op) op #endif /** Return the time remaining until a timeout has elapsed @param mark Starting time stamp @param timeout Time in milliseconds @return Time in milliseconds until the timeout elapses @ingroup MprTime @stability Stable */ PUBLIC MprTicks mprGetRemainingTicks(MprTicks mark, MprTicks timeout); /** Get the elapsed time since a ticks mark. Create the ticks mark with mprGetTicks() @param mark Starting time stamp @returns the time elapsed since the mark was taken. @ingroup MprTime @stability Stable */ PUBLIC MprTicks mprGetElapsedTicks(MprTicks mark); /** Get the elapsed time since a starting time mark. @param mark Starting time created via mprGetTime() @returns the time elapsed since the mark was taken. @ingroup MprTime @stability Stable */ PUBLIC MprTime mprGetElapsedTime(MprTime mark); /* Convert a time structure into a time value using local time. @param timep Pointer to a time structure @return a time value @ingroup MprTime @stability Stable */ PUBLIC MprTime mprMakeTime(struct tm *timep); /* Convert a time structure into a time value using UTC time. @param timep Pointer to a time structure @return a time value @ingroup MprTime @stability Stable */ PUBLIC MprTime mprMakeUniversalTime(struct tm *tm); /** Constants for mprParseTime */ #define MPR_LOCAL_TIMEZONE MAXINT /**< Use local timezone */ #define MPR_UTC_TIMEZONE 0 /**< Use UTC timezone */ /* Parse a string into a time value @description Try to intelligently parse a date. This is a tolerant parser. It is not validating and will do its best to parse any possible date string. Supports the following date/time formats: \n\n ISO dates: 2009-05-21t16:06:05.000z \n\n Date: 07/28/2014, 07/28/08, Jan/28/2014, Jaunuary-28-2014, 28-jan-2014. \n\n Support date order: dd/mm/yy, mm/dd/yy and yyyy/mm/dd \n\n Support separators "/", ".", "-" \n\n Timezones: GMT|UTC[+-]NN[:]NN \n\n Time: 10:52[:23] \n\n @param time Pointer to a time value to receive the parsed time value @param dateString String to parse @param timezone Timezone in which to interpret the date @param defaults Date default values to use for missing components @returns Zero if successful @ingroup MprTime @stability Stable */ PUBLIC int mprParseTime(MprTime *time, cchar *dateString, int timezone, struct tm *defaults); /** Get the current timezone offset for a given time @description Calculate the current timezone (including DST) @param when Time to examine to extract the timezone @returns Returns a timezone offset in msec. Local time == (UTC + offset). @ingroup MprTime @stability Stable */ PUBLIC int mprGetTimeZoneOffset(MprTime when); /*********************************** Lists ************************************/ /* List flags */ #define MPR_OBJ_LIST 0x1 /**< Object is a hash */ #define MPR_LIST_STATIC_VALUES 0x20 /**< Flag for #mprCreateList when values are permanent */ #define MPR_LIST_STABLE 0x40 /**< Contents are stable or only accessed by one thread. Does not need thread locking */ /** List data structure. @description The MprList is a dynamic, growable list suitable for storing pointers to arbitrary objects. @see MprList MprListCompareProc mprAddItem mprAddNullItem mprAppendList mprClearList mprCloneList mprCopyList mprCreateKeyPair mprCreateList mprGetFirstItem mprGetItem mprGetLastItem mprGetListCapacity mprGetListLength mprGetNextItem mprGetPrevItem mprInitList mprInsertItemAtPos mprLookupItem mprLookupStringItem mprPopItem mprPushItem mprRemoveItem mprRemoveItemAtPos mprRemoveRangeOfItems mprRemoveStringItem mprSetItem mprSetListLimits mprSortList @defgroup MprList MprList @stability Internal. */ typedef struct MprList { int flags; /**< Control flags */ int size; /**< Current list capacity */ int length; /**< Current length of the list contents */ int maxSize; /**< Maximum capacity */ MprMutex *mutex; /**< Multithread lock */ void **items; /**< List item data */ } MprList; /** List comparison procedure for sorting @description Callback function signature used by #mprSortList @param arg1 First list item to compare @param arg2 Second list item to compare @returns Return zero if the items are equal. Return -1 if the first arg is less than the second. Otherwise return 1. @ingroup MprList @stability Stable. */ typedef int (*MprListCompareProc)(cvoid *arg1, cvoid *arg2); /** Add an item to a list @description Add the specified item to the list. The list must have been previously created via mprCreateList. The list will grow as required to store the item @param list List pointer returned from #mprCreateList @param item Pointer to item to store @return Returns a positive list index for the inserted item. If the item cannot be inserted due to a memory allocation failure, -1 is returned @ingroup MprList @stability Stable. */ PUBLIC int mprAddItem(MprList *list, cvoid *item); /** Add a null item to the list. @description Add a null item to the list. This item does not count in the length returned by #mprGetListLength and will not be visible when iterating using #mprGetNextItem. @ingroup MprList @stability Stable. */ PUBLIC int mprAddNullItem(MprList *list); /** Append a list @description Append the contents of one list to another. The list will grow as required to store the item @param list List pointer returned from #mprCreateList @param add List whose contents are added @return Returns a pointer to the original list if successful. Returns NULL on memory allocation errors. @ingroup MprList @stability Stable. */ PUBLIC MprList *mprAppendList(MprList *list, MprList *add); /** Clears the list of all items. @description Resets the list length to zero and clears all items. @param list List pointer returned from mprCreateList. @ingroup MprList @stability Stable. */ PUBLIC void mprClearList(MprList *list); /** Clone a list and all elements @description Copy the contents of a list into a new list. @param src Source list to copy @return Returns a new list reference @ingroup MprList @stability Stable. */ PUBLIC MprList *mprCloneList(MprList *src); /** Copy list contents @description Copy the contents of a list into an existing list. The destination list is cleared first and has its dimensions set to that of the source clist. @param dest Destination list for the copy @param src Source list @return Returns zero if successful, otherwise a negative MPR error code. @ingroup MprList @stability Stable. */ PUBLIC int mprCopyListContents(MprList *dest, MprList *src); /** Create a list. @description Creates an empty list. MprList's can store generic pointers. They automatically grow as required when items are added to the list. @param size Initial capacity of the list. Set to < 0 to get a growable list with a default initial size. Set to 0 to to create the list but without any initial list storage. Then call mprSetListLimits to define the initial and maximum list size. @param flags Control flags. Possible values are: MPR_LIST_STATIC_VALUES to indicate list items are static and should not be marked for GC. MPR_LIST_STABLE to create an optimized list for private use that is not thread-safe. @return Returns a pointer to the list. @ingroup MprList @stability Stable. */ PUBLIC MprList *mprCreateList(int size, int flags); /** Create a list of words @description Create a list of words from the given string. The word separators are white space and comma. @param str String containing white space or comma separated words @return Returns a list of words @ingroup MprList @stability Stable */ PUBLIC MprList *mprCreateListFromWords(cchar *str); /** Get the first item in the list. @description Returns the value of the first item in the list. After calling this routine, the remaining list items can be walked using mprGetNextItem. @param list List pointer returned from mprCreateList. @ingroup MprList @stability Stable. */ PUBLIC void *mprGetFirstItem(MprList *list); #if DOXYGEN || 1 /** Get an list item. @description Get an list item specified by its index. @param list List pointer returned from mprCreateList. @param index Item index into the list. Indexes have a range from zero to the lenghth of the list - 1. @ingroup MprList @stability Stable. */ PUBLIC void *mprGetItem(MprList *list, int index); #else #define mprGetItem(lp, index) (index < 0 || index >= lp->length) ? 0 : lp->items[index]; #endif /** Get the last item in the list. @description Returns the value of the last item in the list. After calling this routine, the remaining list items can be walked using mprGetPrevItem. @param list List pointer returned from mprCreateList. @ingroup MprList @stability Stable. */ PUBLIC void *mprGetLastItem(MprList *list); /** Get the current capacity of the list. @description Returns the capacity of the list. This will always be equal to or greater than the list length. @param list List pointer returned from mprCreateList. @ingroup MprList @stability Stable. */ PUBLIC int mprGetListCapacity(MprList *list); /** Get the number of items in the list. @description Returns the number of items in the list. This will always be less than or equal to the list capacity. @param list List pointer returned from mprCreateList. @ingroup MprList @stability Stable. */ PUBLIC int mprGetListLength(MprList *list); /** Get the next item in the list. @description Returns the value of the next item in the list. Before calling this routine, mprGetFirstItem must be called to initialize the traversal of the list. @param list List pointer returned from mprCreateList. @param lastIndex Pointer to an integer that will hold the last index retrieved. @return Next item in list or null for an empty list or after the last item. @ingroup MprList @stability Stable. */ PUBLIC void *mprGetNextItem(MprList *list, int *lastIndex); /** Get the next item in a stable list. This is an optimized version of mprGetNextItem. @description Returns the value of the next item in the list. Before calling this routine, mprGetFirstItem must be called to initialize the traversal of the list. @param list List pointer returned from mprCreateList. @param lastIndex Pointer to an integer that will hold the last index retrieved. @return Next item in list @ingroup MprList @internal @stability Stable */ PUBLIC void *mprGetNextStableItem(MprList *list, int *lastIndex); /** Get the previous item in the list. @description Returns the value of the previous item in the list. Before calling this routine, mprGetFirstItem and/or mprGetNextItem must be called to initialize the traversal of the list. @param list List pointer returned from mprCreateList. @param lastIndex Pointer to an integer that will hold the last index retrieved. @ingroup MprList @stability Stable. */ PUBLIC void *mprGetPrevItem(MprList *list, int *lastIndex); /** Initialize a list structure @description If a list is statically declared inside another structure, mprInitList can be used to initialize it before use. @param list Reference to the MprList struct. @param flags Control flags. Possible values are: MPR_LIST_STATIC_VALUES to indicate list items are static and should not be marked for GC. MPR_LIST_STABLE to create an optimized list for private use that is not thread-safe. @ingroup MprList @stability Stable. */ PUBLIC void mprInitList(MprList *list, int flags); /** Insert an item into a list at a specific position @description Insert the item into the list before the specified position. The list will grow as required to store the item @param list List pointer returned from #mprCreateList @param index Location at which to store the item. The previous item at this index is moved up to make room. @param item Pointer to item to store @return Returns the position index (positive integer) if successful. If the item cannot be inserted due to a memory allocation failure, -1 is returned @ingroup MprList @stability Stable. */ PUBLIC int mprInsertItemAtPos(MprList *list, int index, cvoid *item); /** Convert a list of strings to a single string. This uses the specified join string between the elements. @param list List pointer returned from mprCreateList. @param join String to use as the element join string. May be null. @ingroup MprList @stability Stable */ PUBLIC char *mprListToString(MprList *list, cchar *join); /** Find an item and return its index. @description Search for an item in the list and return its index. @param list List pointer returned from mprCreateList. @param item Pointer to value stored in the list. @return Positive list index if found, otherwise a negative MPR error code. @ingroup MprList @stability Stable. */ PUBLIC int mprLookupItem(MprList *list, cvoid *item); /** Find a string item and return its index. @description Search for the first matching string in the list and return its index. @param list List pointer returned from mprCreateList. @param str Pointer to string to look for. @return Positive list index if found, otherwise a negative MPR error code. @ingroup MprList @stability Stable. */ PUBLIC int mprLookupStringItem(MprList *list, cchar *str); /** Remove an item from the list @description Search for a specified item and then remove it from the list. @param list List pointer returned from mprCreateList. @param item Item pointer to remove. @return Returns the positive index of the removed item, otherwise a negative MPR error code. @ingroup MprList @stability Stable. */ PUBLIC int mprRemoveItem(MprList *list, cvoid *item); /** Remove an item from the list @description Removes the element specified by \a index, from the list. The list index is provided by mprInsertItem. @return Returns the positive index of the removed item, otherwise a negative MPR error code. @ingroup MprList @stability Stable. */ PUBLIC int mprRemoveItemAtPos(MprList *list, int index); /** Remove the last item from the list @description Remove the item at the highest index position. @param list List pointer returned from mprCreateList. @return Returns the positive index of the removed item, otherwise a negative MPR error code. @ingroup MprList @stability Stable. */ PUBLIC int mprRemoveLastItem(MprList *list); /** Remove a range of items from the list. @description Remove a range of items from the list. The range is specified from the \a start index up to and including the \a end index. @param list List pointer returned from mprCreateList. @param start Starting item index to remove (inclusive) @param end Ending item index to remove (inclusive) @return Returns zero if successful, otherwise a negative MPR error code. @ingroup MprList @stability Stable. */ PUBLIC int mprRemoveRangeOfItems(MprList *list, int start, int end); /** Remove a string item from the list @description Search for the first matching string and then remove it from the list. @param list List pointer returned from mprCreateList. @param str String value to remove. @return Returns the positive index of the removed item, otherwise a negative MPR error code. @ingroup MprList @stability Stable. */ PUBLIC int mprRemoveStringItem(MprList *list, cchar *str); /** Set a list item @description Update the list item stored at the specified index @param list List pointer returned from mprCreateList. @param index Location to update @param item Pointer to item to store @return Returns the old item previously at that location index @ingroup MprList @stability Stable. */ PUBLIC void *mprSetItem(MprList *list, int index, cvoid *item); /** Define the list size limits @description Define the list initial size and maximum size it can grow to. @param list List pointer returned from mprCreateList. @param initialSize Initial size for the list. This call will allocate space for at least this number of items. @param maxSize Set the maximum limit the list can grow to become. @return Returns zero if successful, otherwise a negative MPR error code. @ingroup MprList @stability Stable. */ PUBLIC int mprSetListLimits(MprList *list, int initialSize, int maxSize); /** Quicksort callback function @description This is a quicksort callback with a context argument. @param p1 Pointer to first element @param p2 Pointer to second element @param ctx Context argument to provide to comparison function @return -1, 0, or 1, depending on if the elements are p1 < p2, p1 == p2 or p1 > p2 @ingroup MprList @stability Stable */ typedef int (*MprSortProc)(cvoid *p1, cvoid *p2, void *ctx); /** Quicksort @description This is a quicksort with a context argument. @param base Base of array to sort @param num Number of array elements @param width Width of array elements @param compare Comparison function @param ctx Context argument to provide to comparison function @return The base array for chaining @ingroup MprList @stability Stable */ PUBLIC void *mprSort(void *base, ssize num, ssize width, MprSortProc compare, void *ctx); /** Sort a list @description Sort a list using the sort ordering dictated by the supplied compare function. @param list List pointer returned from mprCreateList. @param compare Comparison function. If null, then a default string comparison is used. @param ctx Context to provide to comparison function @return The sorted list @ingroup MprList @stability Stable */ PUBLIC MprList *mprSortList(MprList *list, MprSortProc compare, void *ctx); /** Key value pairs for use with MprList or MprKey @ingroup MprList @stability Stable */ typedef struct MprKeyValue { void *key; /**< Key string (managed) */ void *value; /**< Associated value for the key (managed) */ int flags; /**< General flags word */ } MprKeyValue; /** Create a key / value pair @description Allocate and initialize a key value pair for use by the MprList or MprHash modules. @param key Key string @param value Key value string @param flags Flags value @returns An initialized MprKeyValue @ingroup MprList @stability Stable */ PUBLIC MprKeyValue *mprCreateKeyPair(cchar *key, cchar *value, int flags); /** Pop an item @description Treat the list as a stack and pop the last pushed item @param list List pointer returned from mprCreateList. @return Returns the last pushed item. If the list is empty, returns NULL. @ingroup MprList @stability Stable */ PUBLIC void *mprPopItem(MprList *list); /** Push an item onto the list @description Treat the list as a stack and push the last pushed item @param list List pointer returned from mprCreateList. @param item Item to push onto the list @return Returns a positive integer list index for the inserted item. If the item cannot be inserted due to a memory allocation failure, -1 is returned @ingroup MprList @stability Stable */ PUBLIC int mprPushItem(MprList *list, cvoid *item); #define MPR_GET_ITEM(list, index) list->items[index] #define ITERATE_ITEMS(list, item, next) next = 0; (item = mprGetNextItem(list, &next)) != 0; #define ITERATE_STABLE_ITEMS(list, item, next) next = 0; (item = mprGetNextStableItem(list, &next)) != 0; #define mprGetListLength(lp) ((lp) ? (lp)->length : 0) /********************************** Logging ***********************************/ /** Logging Services @defgroup MprLog MprLog @see MprLogHandler mprAssert mprError mprGetLogFile mprGetLogHandler mprInfo mprLog mprRawLog mprDebug mprSetLogFile mprSetLogHandler mprSetLogLevel mprStaticError mprUsingDefaultLogHandler mprWarn @stability Internal */ typedef struct MprLog { int dummy; } MprLog; /** Log handler callback type. @description Callback prototype for the log handler. Used by mprSetLogHandler to define a message logging handler to process log and error messages. See #mprLog for more details. @param file Source filename. Derived by using __FILE__. @param line Source line number. Derived by using __LINE__. @param flags Error flags. @param tags List of space separated tag words. @param level Message logging level. Levels are 0-5 with five being the most verbose. @param msg Message being logged. @ingroup MprLog @stability Stable */ typedef void (*MprLogHandler)(cchar *tags, int level, cchar *msg); /** Output an assure assertion failed message. @description This will emit an assure assertion failed message to the standard error output. It may bypass the logging system. @param loc Source code location string. Use MPR_LOC to define a file name and line number string suitable for this parameter. @param msg Simple string message to output @ingroup MprLog @stability Stable */ PUBLIC void mprAssert(cchar *loc, cchar *msg); /** Initialize the log service @ingroup MprLog @stability Internal */ PUBLIC void mprCreateLogService(void); /** Backup a log @param path Base log filename @param count Count of archived logs to keep @ingroup MprLog @stability Stable */ PUBLIC int mprBackupLog(cchar *path, int count); /** Default MPR log handler @param tags Descriptive tag words to classify this message. @param level Logging level for this message. The level is 0-5 with five being the most verbose. @param msg Message to log @ingroup MprLog @stability Stable */ PUBLIC void mprDefaultLogHandler(cchar *tags, int level, cchar *msg); /** Log an error message. @description Send an error message to the MPR debug logging subsystem. The message will be to the log handler defined by #mprSetLogHandler. It is up to the log handler to respond appropriately and log the message. This will invoke mprLog with a severity tag of "error". @param fmt Printf style format string. Variable number of arguments to @param ... Variable number of arguments for printf data @ingroup MprLog @stability Stable */ PUBLIC void mprError(cchar *fmt, ...) PRINTF_ATTRIBUTE(1,2); /** Get the log file object @description Returns the MprFile object used for logging @returns An MprFile object for logging @ingroup MprLog @stability Stable */ PUBLIC struct MprFile *mprGetLogFile(void); /** Get the current MPR debug log handler. @description Get the log handler defined via #mprSetLogHandler @returns A function of the signature #MprLogHandler @ingroup MprLog @stability Stable */ PUBLIC MprLogHandler mprGetLogHandler(void); #if DOXYGEN /** Write a message to the error log file. @description Send a message to the MPR error logging subsystem. The purpose of the error log is to record essential configuration and error conditions. Per-request trace typically is sent to a separate trace log. \n\n By default, error log messages are sent to the standard error output. Applications may redirect output by installing a log handler using #mprSetLogHandler. \n\n Log messages should be a single text line to facilitate machine processing of log files. Descriptive tag words may be provided to indicate a severity level and to classifiy messages. By convention, tags may include one of the severity levels defined in RFC 5424: "debug", "info", "notice", "warn", "error", "critical". Messages using the "error", "critical" tags should use a level of zero. Tags should be space separated. By convention, specify the RFC tag name first in a list of tags. \n\n The default log handler emits messages in three formats depending on whether MPR_LOG_DETAILED is provided to #mprStartLogging and the value of the tags parameter. If MPR_LOG_DETAILED and tags are supplied, the format is: "MM/DD/YY HH:MM:SS LEVEL TAGS, Message". Otherwise a a simplified output format is used: "Name: severity: message", where severity is set to "error" for level 0 messages. This is useful for utility programs. If tags are null, the message is output raw, without any any prefixes. \n\n Logging typically is enabled in both debug and release builds and may be controlled via the build define ME_MPR_LOGGING which is typically set via the MakeMe setting "logging: true". \n\n The #mprDebug API may be used to emit log messages only in debug builds. \n\n If level zero is used, the message is also sent to any relevant operating system logging facility such as syslog or the Windows event database. \n\n It is good practice to only include debug trace at levels above level 2 so that essential error messages are clearly visible in the error log and are not swamped by debug messages. @param tags Descriptive space separated tag words to classify this message. Tag words may be provided to indicate a severity level and to classifiy messages. By convention, tags may include one of the severity levels defined in RFC 5424: "debug", "info", "notice", "warn", "error", "critical". Messages using the "error", "critical" tags should use a level of zero. Tags should be space separated. By convention, specify the RFC tag name first in a list of tags. @param level Logging level for this message. The level is 0-5 with five being the most verbose. @param fmt Printf style format string. Variable number of arguments to print @param ... Variable number of arguments for printf data @remarks mprLog is highly useful as a debugging aid. @ingroup MprLog @stability Stable */ PUBLIC void mprLog(cchar *tags, int level, cchar *fmt, ...); #endif PUBLIC void mprLogProc(cchar *tags, int level, cchar *fmt, ...) PRINTF_ATTRIBUTE(3,4); /** Show the product configuration at the start of the log file @ingroup MprLog @stability Stable */ PUBLIC void mprLogConfig(void); /** Set the log rotation parameters @param logSize If the size is zero, then the log file will be rotated on each application boot. Otherwise, the log file will be rotated if on application boot, the log file is larger than this size. @param backupCount Count of the number of log files to keep @param flags Set to MPR_LOG_ANEW to truncate existing files (after backup). @ingroup MprLog @stability Stable */ PUBLIC void mprSetLogBackup(ssize logSize, int backupCount, int flags); /** Set a file to be used for logging @param file MprFile object instance @stability Stable */ PUBLIC void mprSetLogFile(struct MprFile *file); /** Set an MPR debug log handler. @description Defines a callback handler for MPR debug and error log messages. When output is sent to the debug channel, the log handler will be invoked to accept the output message. @param handler Callback handler @return Prior log handler @stability Stable */ PUBLIC MprLogHandler mprSetLogHandler(MprLogHandler handler); /** Start logging @param logSpec Set the log file name and level. The format is "pathName[:level]". The level is a verbosity level from 0 to 5 with 5 being the most verbose. The following levels are generally observed: