/* +----------------------------------------------------------------------+ | Swoole | +----------------------------------------------------------------------+ | This source file is subject to version 2.0 of the Apache license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.apache.org/licenses/LICENSE-2.0.html | | If you did not receive a copy of the Apache2.0 license and are unable| | to obtain it through the world-wide-web, please send a note to | | license@swoole.com so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Tianfeng Han | +----------------------------------------------------------------------+ */ #ifndef SWOOLE_H_ #define SWOOLE_H_ #if defined(HAVE_CONFIG_H) && !defined(COMPILE_DL_SWOOLE) #include "config.h" #endif #ifdef SW_STATIC_COMPILATION #include "php_config.h" #endif #ifdef __cplusplus extern "C" { #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #include #if defined(HAVE_CPU_AFFINITY) #ifdef __FreeBSD__ #include #include #include typedef cpuset_t cpu_set_t; #else #include #endif #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __MACH__ #include #include #include #define ORWL_NANO (+1.0E-9) #define ORWL_GIGA UINT64_C(1000000000) static double orwl_timebase = 0.0; static uint64_t orwl_timestart = 0; #ifndef HAVE_CLOCK_GETTIME int clock_gettime(clock_id_t which_clock, struct timespec *t); #endif #endif #ifndef HAVE_DAEMON int daemon(int nochdir, int noclose); #endif /*----------------------------------------------------------------------------*/ #ifndef ulong #define ulong unsigned long #endif typedef unsigned long ulong_t; #if defined(__GNUC__) #if __GNUC__ >= 3 #define sw_inline inline __attribute__((always_inline)) #else #define sw_inline inline #endif #elif defined(_MSC_VER) #define sw_inline __forceinline #else #define sw_inline inline #endif #if defined(__GNUC__) && __GNUC__ >= 4 #define SW_API __attribute__ ((visibility("default"))) #else #define SW_API #endif #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) #define MAP_ANONYMOUS MAP_ANON #endif #ifndef SOCK_NONBLOCK #define SOCK_NONBLOCK O_NONBLOCK #endif #ifndef CLOCK_REALTIME #define CLOCK_REALTIME 0 #endif #if !defined(__GNUC__) || __GNUC__ < 3 #define __builtin_expect(x, expected_value) (x) #endif #ifndef likely #define likely(x) __builtin_expect(!!(x), 1) #endif #ifndef unlikely #define unlikely(x) __builtin_expect(!!(x), 0) #endif #define SW_START_LINE "-------------------------START----------------------------" #define SW_END_LINE "-------------------------END------------------------------" #define SW_ECHO_GREEN "\e[32m%s\e[0m" #define SW_ECHO_RED "\e[31m%s\e[0m" #define SW_ECHO_YELLOW "\e[33m%s\e[0m" #define SW_ECHO_CYAN_BLUE "\e[36m%s\e[0m" #define SW_SPACE ' ' #define SW_CRLF "\r\n" #define SW_CRLF_LEN 2 #define SW_ASCII_CODE_0 64 #define SW_ASCII_CODE_Z 106 /*----------------------------------------------------------------------------*/ #include "swoole_config.h" #include "atomic.h" #include "hashmap.h" #include "list.h" #include "heap.h" #include "RingQueue.h" #include "array.h" #include "error.h" #define SW_MAX_UINT 4294967295 #define SW_MAX_INT 2147483647 #ifndef MAX #define MAX(a, b) (a)>(b)?a:b; #endif #ifndef MIN #define MIN(a, b) (a)<(b)?a:b; #endif #define SW_STRL(s) s, sizeof(s) #define SW_START_SLEEP usleep(100000) //sleep 1s,wait fork and pthread_create #ifdef SW_USE_JEMALLOC #include #define sw_malloc je_malloc #define sw_free je_free #define sw_calloc je_calloc #define sw_realloc je_realloc #else #define sw_malloc malloc #define sw_free free #define sw_calloc calloc #define sw_realloc realloc #endif static sw_inline char* swoole_strdup(const char *s) { size_t l = strlen(s) + 1; char *p = (char *)sw_malloc(l); memcpy(p, s, l); return p; } static sw_inline char* swoole_strndup(const char *s, size_t n) { char *p = (char *)sw_malloc(n + 1); strncpy(p, s, n); p[n] = '\0'; return p; } #if defined(SW_USE_JEMALLOC) || defined(SW_USE_TCMALLOC) #define sw_strdup swoole_strdup #define sw_strndup swoole_strndup #else #define sw_strdup strdup #define sw_strndup strndup #endif #define METHOD_DEF(class,name,...) class##_##name(class *object, ##__VA_ARGS__) #define METHOD(class,name,...) class##_##name(object, ##__VA_ARGS__) //------------------------------------------------------------------------------- #define SW_OK 0 #define SW_ERR -1 #define SW_AGAIN -2 #define SW_BUSY -3 #define SW_DONE -4 #define SW_DECLINED -5 #define SW_ABORT -6 //------------------------------------------------------------------------------- enum swReturnType { SW_CONTINUE = 1, SW_WAIT = 2, SW_CLOSE = 3, SW_ERROR = 4, SW_READY = 5, }; //------------------------------------------------------------------------------- enum swFd_type { SW_FD_TCP = 0, //tcp socket SW_FD_LISTEN = 1, //server socket SW_FD_CLOSE = 2, //socket closed SW_FD_ERROR = 3, //socket error SW_FD_UDP = 4, //udp socket SW_FD_PIPE = 5, //pipe SW_FD_STREAM = 6, //stream socket SW_FD_WRITE = 7, //fd can write SW_FD_TIMER = 8, //timer fd SW_FD_AIO = 9, //linux native aio SW_FD_SIGNAL = 11, //signalfd SW_FD_DNS_RESOLVER = 12, //dns resolver SW_FD_INOTIFY = 13, //server socket SW_FD_USER = 15, //SW_FD_USER or SW_FD_USER+n: for custom event SW_FD_STREAM_CLIENT = 16, //swClient stream SW_FD_DGRAM_CLIENT = 17, //swClient dgram }; enum swBool_type { SW_TRUE = 1, SW_FALSE = 0, }; enum swEvent_type { SW_EVENT_DEAULT = 256, SW_EVENT_READ = 1u << 9, SW_EVENT_WRITE = 1u << 10, SW_EVENT_ERROR = 1u << 11, SW_EVENT_ONCE = 1u << 12, }; enum swPipe_type { SW_PIPE_READ = 0, SW_PIPE_WRITE = 1, }; enum swGlobal_hook_type { SW_GLOBAL_HOOK_BEFORE_SERVER_START, SW_GLOBAL_HOOK_BEFORE_CLIENT_START, }; //------------------------------------------------------------------------------- enum swServer_mode { SW_MODE_BASE = 1, SW_MODE_THREAD = 2, SW_MODE_PROCESS = 3, SW_MODE_SINGLE = 4, }; //------------------------------------------------------------------------------- enum swSocket_type { SW_SOCK_TCP = 1, SW_SOCK_UDP = 2, SW_SOCK_TCP6 = 3, SW_SOCK_UDP6 = 4, SW_SOCK_UNIX_DGRAM = 5, //unix sock dgram SW_SOCK_UNIX_STREAM = 6, //unix sock stream }; #define SW_SOCK_SSL (1u << 9) //------------------------------------------------------------------------------- enum swLog_level { SW_LOG_DEBUG = 0, SW_LOG_TRACE, SW_LOG_INFO, SW_LOG_NOTICE, SW_LOG_WARNING, SW_LOG_ERROR, }; //------------------------------------------------------------------------------- enum swFactory_dispatch_mode { SW_DISPATCH_ROUND = 1, SW_DISPATCH_FDMOD = 2, SW_DISPATCH_QUEUE = 3, SW_DISPATCH_IPMOD = 4, SW_DISPATCH_UIDMOD = 5, SW_DISPATCH_USERFUNC = 6, SW_DISPATCH_STREAM = 7, }; enum swWorker_status { SW_WORKER_BUSY = 1, SW_WORKER_IDLE = 2, SW_WORKER_DEL = 3, }; //------------------------------------------------------------------------------- #define swWarn(str,...) SwooleGS->lock_2.lock(&SwooleGS->lock_2);\ snprintf(sw_error,SW_ERROR_MSG_SIZE,"%s: " str,__func__,##__VA_ARGS__);\ swLog_put(SW_LOG_WARNING, sw_error);\ SwooleGS->lock_2.unlock(&SwooleGS->lock_2) #define swNotice(str,...) if (SW_LOG_NOTICE >= SwooleG.log_level){\ SwooleGS->lock_2.lock(&SwooleGS->lock_2);\ snprintf(sw_error,SW_ERROR_MSG_SIZE,str,##__VA_ARGS__);\ swLog_put(SW_LOG_NOTICE, sw_error);\ SwooleGS->lock_2.unlock(&SwooleGS->lock_2);} #if defined(SW_DEBUG) || defined(SW_LOG_TRACE_OPEN) #define swTrace(str,...) if (SW_LOG_TRACE >= SwooleG.log_level){\ SwooleGS->lock_2.lock(&SwooleGS->lock_2);\ snprintf(sw_error, SW_ERROR_MSG_SIZE, str, ##__VA_ARGS__);\ swLog_put(SW_LOG_TRACE, sw_error);\ SwooleGS->lock_2.unlock(&SwooleGS->lock_2);} #else #define swTrace(str,...) #endif #define swError(str,...) SwooleGS->lock_2.lock(&SwooleGS->lock_2);\ snprintf(sw_error, SW_ERROR_MSG_SIZE, str, ##__VA_ARGS__);\ swLog_put(SW_LOG_ERROR, sw_error);\ SwooleGS->lock_2.unlock(&SwooleGS->lock_2);\ exit(1) #define swSysError(str,...) SwooleGS->lock_2.lock(&SwooleGS->lock_2);\ snprintf(sw_error,SW_ERROR_MSG_SIZE,"%s(:%d): " str " Error: %s[%d].",__func__,__LINE__,##__VA_ARGS__,strerror(errno),errno);\ swLog_put(SW_LOG_ERROR, sw_error);\ SwooleG.error=errno;\ SwooleGS->lock_2.unlock(&SwooleGS->lock_2) #define swoole_error_log(level, __errno, str, ...) do{SwooleG.error=__errno;\ if (level >= SwooleG.log_level){\ snprintf(sw_error, SW_ERROR_MSG_SIZE, "%s (ERROR %d): " str,__func__,__errno,##__VA_ARGS__);\ SwooleGS->lock_2.lock(&SwooleGS->lock_2);\ swLog_put(level, sw_error);\ SwooleGS->lock_2.unlock(&SwooleGS->lock_2);}}while(0) #ifdef SW_DEBUG_REMOTE_OPEN #define swDebug(str,...) int __debug_log_n = snprintf(sw_error, SW_ERROR_MSG_SIZE, str, ##__VA_ARGS__);\ write(SwooleG.debug_fd, sw_error, __debug_log_n); #elif defined(SW_DEBUG) #define swDebug(str,...) if (SW_LOG_DEBUG >= SwooleG.log_level){\ SwooleGS->lock_2.lock(&SwooleGS->lock_2);\ snprintf(sw_error, SW_ERROR_MSG_SIZE, "%s(:%d): " str, __func__, __LINE__, ##__VA_ARGS__);\ swLog_put(SW_LOG_DEBUG, sw_error);\ SwooleGS->lock_2.unlock(&SwooleGS->lock_2);} #else #define swDebug(str,...) #endif enum swTraceType { SW_TRACE_SERVER = 1u << 1, SW_TRACE_CLIENT = 1u << 2, SW_TRACE_BUFFER = 1u << 3, SW_TRACE_CONN = 1u << 4, SW_TRACE_EVENT = 1u << 5, SW_TRACE_WORKER = 1u << 6, SW_TRACE_MEMORY = 1u << 7, SW_TRACE_REACTOR = 1u << 8, SW_TRACE_PHP = 1u << 9, SW_TRACE_HTTP2 = 1u << 10, SW_TRACE_EOF_PROTOCOL = 1u << 11, SW_TRACE_LENGTH_PROTOCOL = 1u << 12, SW_TRACE_CLOSE = 1u << 13, SW_TRACE_HTTP_CLIENT = 1u << 14, SW_TRACE_COROUTINE = 1u << 15, SW_TRACE_REDIS_CLIENT = 1u << 16, SW_TRACE_MYSQL_CLIENT = 1u << 17, SW_TRACE_AIO = 1u << 18, SW_TRACE_SSL = 1u << 19, }; #ifdef SW_LOG_TRACE_OPEN #define swTraceLog(what,str,...) if (SW_LOG_TRACE >= SwooleG.log_level && (what & SwooleG.trace_flags)) {\ SwooleGS->lock_2.lock(&SwooleGS->lock_2);\ snprintf(sw_error,SW_ERROR_MSG_SIZE,"%s(:%d): " str, __func__, __LINE__, ##__VA_ARGS__);\ swLog_put(SW_LOG_TRACE, sw_error);\ SwooleGS->lock_2.unlock(&SwooleGS->lock_2);} #else #define swTraceLog(id,str,...) #endif #define swYield() sched_yield() //or usleep(1) //#define swYield() usleep(500000) #define SW_MAX_FDTYPE 32 //32 kinds of event #define SW_ERROR_MSG_SIZE 512 //------------------------------Base-------------------------------- #ifndef uchar typedef unsigned char uchar; #endif #ifdef SW_USE_OPENSSL #include #endif typedef void (*swDestructor)(void *data); typedef void (*swCallback)(void *data); typedef struct { uint32_t id; uint32_t fd :24; uint32_t reactor_id :8; } swSession; typedef struct _swString { size_t length; size_t size; off_t offset; char *str; } swString; typedef void* swObject; typedef struct _swLinkedList_node { struct _swLinkedList_node *prev; struct _swLinkedList_node *next; ulong_t priority; void *data; } swLinkedList_node; typedef struct { uint32_t num; uint8_t type; swLinkedList_node *head; swLinkedList_node *tail; swDestructor dtor; } swLinkedList; typedef struct { union { struct sockaddr_in inet_v4; struct sockaddr_in6 inet_v6; struct sockaddr_un un; } addr; socklen_t len; } swSocketAddress; typedef struct _swConnection { /** * file descript */ int fd; /** * session id */ uint32_t session_id; /** * socket type, SW_SOCK_TCP or SW_SOCK_UDP */ uint16_t socket_type; /** * fd type, SW_FD_TCP or SW_FD_PIPE or SW_FD_TIMERFD */ uint16_t fdtype; int events; //-------------------------------------------------------------- /** * is active * system fd must be 0. en: timerfd, signalfd, listen socket */ uint8_t active; uint8_t connect_notify; uint8_t direct_send; uint8_t ssl_send; //-------------------------------------------------------------- uint8_t listen_wait; uint8_t recv_wait; uint8_t send_wait; uint8_t close_wait; uint8_t overflow; uint8_t high_watermark; uint8_t removed; uint8_t tcp_nopush; uint8_t dontwait; //-------------------------------------------------------------- uint8_t tcp_nodelay; uint8_t ssl_want_read; uint8_t ssl_want_write; uint8_t http_upgrade; uint8_t http2_stream; uint8_t skip_recv; //-------------------------------------------------------------- /** * server is actively close the connection */ uint8_t close_actively; uint8_t closed; uint8_t closing; uint8_t close_reset; /** * protected connection, cannot be closed by heartbeat thread. */ uint8_t protect; uint8_t nonblock; //-------------------------------------------------------------- uint8_t close_notify; uint8_t close_force; //-------------------------------------------------------------- /** * ReactorThread id */ uint16_t from_id; /** * close error code */ uint16_t close_errno; /** * from which socket fd */ sw_atomic_t from_fd; /** * socket address */ swSocketAddress info; /** * link any thing, for kernel, do not use with application. */ void *object; /** * input buffer */ struct _swBuffer *in_buffer; /** * output buffer */ struct _swBuffer *out_buffer; /** * for receive data buffer */ swString *recv_buffer; /** * connect time(seconds) */ time_t connect_time; /** * received time with last data */ time_t last_time; #ifdef SW_BUFFER_RECV_TIME /** * received time(microseconds) with last data */ double last_time_usec; #endif #ifdef SW_USE_TIMEWHEEL uint16_t timewheel_index; #endif /** * bind uid */ uint32_t uid; /** * memory buffer size; */ int buffer_size; /** * upgarde websocket */ uint8_t websocket_status; /** * unfinished data frame */ swString *websocket_buffer; #ifdef SW_USE_OPENSSL SSL *ssl; uint32_t ssl_state; swString ssl_client_cert; #endif sw_atomic_t lock; #ifdef SW_DEBUG size_t total_recv_bytes; size_t total_send_bytes; #endif } swConnection; typedef struct _swProtocol { /* one package: eof check */ uint8_t split_by_eof; uint8_t package_eof_len; //数据缓存结束符长度 char package_eof[SW_DATA_EOF_MAXLEN + 1]; //数据缓存结束符 char package_length_type; //length field type uint8_t package_length_size; uint16_t package_length_offset; //第几个字节开始表示长度 uint16_t package_body_offset; //第几个字节开始计算长度 uint32_t package_max_length; void *private_data; int (*onPackage)(swConnection *conn, char *data, uint32_t length); int (*get_package_length)(struct _swProtocol *protocol, swConnection *conn, char *data, uint32_t length); } swProtocol; typedef int (*swProtocol_length_function)(struct _swProtocol *, swConnection *, char *, uint32_t); //------------------------------String-------------------------------- #define swoole_tolower(c) (u_char) ((c >= 'A' && c <= 'Z') ? (c | 0x20) : c) #define swoole_toupper(c) (u_char) ((c >= 'a' && c <= 'z') ? (c & ~0x20) : c) uint32_t swoole_utf8_decode(u_char **p, size_t n); size_t swoole_utf8_length(u_char *p, size_t n); void swoole_random_string(char *buf, size_t size); char* swoole_get_mimetype(char *file); static sw_inline char *swoole_strlchr(char *p, char *last, char c) { while (p < last) { if (*p == c) { return p; } p++; } return NULL; } static sw_inline size_t swoole_size_align(size_t size, int pagesize) { return size + (pagesize - (size % pagesize)); } static sw_inline void swString_clear(swString *str) { str->length = 0; str->offset = 0; } static sw_inline void swString_free(swString *str) { sw_free(str->str); sw_free(str); } static sw_inline size_t swString_length(swString *str) { return str->length; } static sw_inline size_t swString_size(swString *str) { return str->size; } swString *swString_new(size_t size); swString *swString_dup(const char *src_str, int length); swString *swString_dup2(swString *src); void swString_print(swString *str); void swString_free(swString *str); int swString_append(swString *str, swString *append_str); int swString_append_ptr(swString *str, char *append_str, int length); int swString_write(swString *str, off_t offset, swString *write_str); int swString_write_ptr(swString *str, off_t offset, char *write_str, int length); int swString_extend(swString *str, size_t new_size); char* swString_alloc(swString *str, size_t __size); #define SWSTRING_CURRENT_VL(buffer) buffer->str + buffer->offset, buffer->length - buffer->offset static sw_inline int swString_extend_align(swString *str, size_t _new_size) { size_t align_size = str->size * 2; while (align_size < _new_size) { align_size *= 2; } return swString_extend(str, align_size); } #define swString_length(s) (s->length) #define swString_ptr(s) (s->str) //------------------------------Base-------------------------------- typedef struct _swDataHead { int fd; uint16_t len; int16_t from_id; uint8_t type; uint8_t flags; uint16_t from_fd; #ifdef SW_BUFFER_RECV_TIME double time; #endif } swDataHead; typedef struct _swEvent { int fd; int16_t from_id; uint8_t type; swConnection *socket; } swEvent; typedef struct _swEventData { swDataHead info; char data[SW_BUFFER_SIZE]; } swEventData; typedef struct _swDgramPacket { union { struct in6_addr v6; struct in_addr v4; struct { uint16_t path_length; } un; } addr; uint16_t port; uint32_t length; char data[0]; } swDgramPacket; typedef struct _swSendData { swDataHead info; /** * for big package */ uint32_t length; char *data; } swSendData; typedef struct { off_t offset; size_t length; char filename[0]; } swSendFile_request; //------------------TimeWheel-------------------- typedef struct { uint16_t current; uint16_t size; swHashMap **wheel; } swTimeWheel; typedef void * (*swThreadStartFunc)(void *); typedef int (*swHandle)(swEventData *buf); typedef void (*swSignalHander)(int); typedef struct _swReactor swReactor; typedef int (*swReactor_handle)(swReactor *reactor, swEvent *event); //------------------Pipe-------------------- typedef struct _swPipe { void *object; int blocking; double timeout; int (*read)(struct _swPipe *, void *recv, int length); int (*write)(struct _swPipe *, void *send, int length); int (*getFd)(struct _swPipe *, int master); int (*close)(struct _swPipe *); } swPipe; enum _swPipe_close_which { SW_PIPE_CLOSE_MASTER = 1, SW_PIPE_CLOSE_WORKER = 2, SW_PIPE_CLOSE_READ = 3, SW_PIPE_CLOSE_WRITE = 4, SW_PIPE_CLOSE_BOTH = 0, }; int swPipeBase_create(swPipe *p, int blocking); int swPipeEventfd_create(swPipe *p, int blocking, int semaphore, int timeout); int swPipeUnsock_create(swPipe *p, int blocking, int protocol); int swPipeUnsock_close_ext(swPipe *p, int which); static inline int swPipeNotify_auto(swPipe *p, int blocking, int semaphore) { #ifdef HAVE_EVENTFD return swPipeEventfd_create(p, blocking, semaphore, 0); #else return swPipeBase_create(p, blocking); #endif } void swBreakPoint(void); //------------------Queue-------------------- typedef struct _swQueue_Data { long mtype; /* type of received/sent message */ char mdata[sizeof(swEventData)]; /* text of the message */ } swQueue_data; typedef struct _swMsgQueue { int blocking; int msg_id; int flags; int perms; } swMsgQueue; int swMsgQueue_create(swMsgQueue *q, int blocking, key_t msg_key, int perms); void swMsgQueue_set_blocking(swMsgQueue *q, uint8_t blocking); int swMsgQueue_push(swMsgQueue *q, swQueue_data *in, int data_length); int swMsgQueue_pop(swMsgQueue *q, swQueue_data *out, int buffer_length); int swMsgQueue_stat(swMsgQueue *q, int *queue_num, int *queue_bytes); int swMsgQueue_free(swMsgQueue *q); //------------------Lock-------------------------------------- enum SW_LOCKS { SW_RWLOCK = 1, #define SW_RWLOCK SW_RWLOCK SW_FILELOCK = 2, #define SW_FILELOCK SW_FILELOCK SW_MUTEX = 3, #define SW_MUTEX SW_MUTEX SW_SEM = 4, #define SW_SEM SW_SEM SW_SPINLOCK = 5, #define SW_SPINLOCK SW_SPINLOCK SW_ATOMLOCK = 6, #define SW_ATOMLOCK SW_ATOMLOCK }; enum swDNSLookup_cache_type { SW_DNS_LOOKUP_RANDOM = (1u << 11), }; typedef struct { char *hostname; char *service; int family; int socktype; int protocol; int error; void *result; int count; } swRequest_getaddrinfo; //文件锁 typedef struct _swFileLock { struct flock lock_t; int fd; } swFileLock; //互斥锁 typedef struct _swMutex { pthread_mutex_t _lock; pthread_mutexattr_t attr; } swMutex; #ifdef HAVE_RWLOCK typedef struct _swRWLock { pthread_rwlock_t _lock; pthread_rwlockattr_t attr; } swRWLock; #endif #ifdef HAVE_SPINLOCK typedef struct _swSpinLock { pthread_spinlock_t lock_t; } swSpinLock; #endif typedef struct _swAtomicLock { sw_atomic_t lock_t; uint32_t spin; } swAtomicLock; typedef struct _swSem { key_t key; int semid; } swSem; typedef struct _swLock { int type; union { swMutex mutex; #ifdef HAVE_RWLOCK swRWLock rwlock; #endif #ifdef HAVE_SPINLOCK swSpinLock spinlock; #endif swFileLock filelock; swSem sem; swAtomicLock atomlock; } object; int (*lock_rd)(struct _swLock *); int (*lock)(struct _swLock *); int (*unlock)(struct _swLock *); int (*trylock_rd)(struct _swLock *); int (*trylock)(struct _swLock *); int (*free)(struct _swLock *); } swLock; //Thread Condition typedef struct _swCond { swLock _lock; pthread_cond_t _cond; int (*wait)(struct _swCond *object); int (*timewait)(struct _swCond *object, long, long); int (*notify)(struct _swCond *object); int (*broadcast)(struct _swCond *object); void (*free)(struct _swCond *object); int (*lock)(struct _swCond *object); int (*unlock)(struct _swCond *object); } swCond; #define SW_SHM_MMAP_FILE_LEN 64 typedef struct _swShareMemory_mmap { size_t size; char mapfile[SW_SHM_MMAP_FILE_LEN]; int tmpfd; int key; int shmid; void *mem; } swShareMemory; void *swShareMemory_mmap_create(swShareMemory *object, size_t size, char *mapfile); void *swShareMemory_sysv_create(swShareMemory *object, size_t size, int key); int swShareMemory_sysv_free(swShareMemory *object, int rm); int swShareMemory_mmap_free(swShareMemory *object); //-------------------memory manager------------------------- typedef struct _swMemoryPool { void *object; void* (*alloc)(struct _swMemoryPool *pool, uint32_t size); void (*free)(struct _swMemoryPool *pool, void *ptr); void (*destroy)(struct _swMemoryPool *pool); } swMemoryPool; typedef struct _swFixedPool_slice { uint8_t lock; struct _swFixedPool_slice *next; struct _swFixedPool_slice *pre; char data[0]; } swFixedPool_slice; typedef struct _swFixedPool { void *memory; size_t size; swFixedPool_slice *head; swFixedPool_slice *tail; /** * total memory size */ uint32_t slice_num; /** * memory usage */ uint32_t slice_use; /** * Fixed slice size, not include the memory used by swFixedPool_slice */ uint32_t slice_size; /** * use shared memory */ uint8_t shared; } swFixedPool; /** * FixedPool, random alloc/free fixed size memory */ swMemoryPool* swFixedPool_new(uint32_t slice_num, uint32_t slice_size, uint8_t shared); swMemoryPool* swFixedPool_new2(uint32_t slice_size, void *memory, size_t size); swMemoryPool* swMalloc_new(); /** * RingBuffer, In order for malloc / free */ swMemoryPool *swRingBuffer_new(uint32_t size, uint8_t shared); /** * Global memory, the program life cycle only malloc / free one time */ swMemoryPool* swMemoryGlobal_new(uint32_t pagesize, uint8_t shared); void swFixedPool_debug(swMemoryPool *pool); /** * alloc shared memory */ void* sw_shm_malloc(size_t size); void sw_shm_free(void *ptr); void* sw_shm_calloc(size_t num, size_t _size); int sw_shm_protect(void *addr, int flags); void* sw_shm_realloc(void *ptr, size_t new_size); #ifdef HAVE_RWLOCK int swRWLock_create(swLock *lock, int use_in_process); #endif int swSem_create(swLock *lock, key_t key); int swMutex_create(swLock *lock, int use_in_process); int swMutex_lockwait(swLock *lock, int timeout_msec); int swFileLock_create(swLock *lock, int fd); #ifdef HAVE_SPINLOCK int swSpinLock_create(swLock *object, int spin); #endif int swAtomicLock_create(swLock *object, int spin); int swCond_create(swCond *cond); typedef struct _swThreadParam { void *object; int pti; } swThreadParam; extern int16_t sw_errno; extern char sw_error[SW_ERROR_MSG_SIZE]; enum swProcessType { SW_PROCESS_MASTER = 1, SW_PROCESS_WORKER = 2, SW_PROCESS_MANAGER = 3, SW_PROCESS_TASKWORKER = 4, SW_PROCESS_USERWORKER = 5, }; #define swIsMaster() (SwooleG.process_type==SW_PROCESS_MASTER) #define swIsWorker() (SwooleG.process_type==SW_PROCESS_WORKER) #define swIsTaskWorker() (SwooleG.process_type==SW_PROCESS_TASKWORKER) #define swIsManager() (SwooleG.process_type==SW_PROCESS_MANAGER) #define swIsUserWorker() (SwooleG.process_type==SW_PROCESS_USERWORKER) //----------------------tool function--------------------- int swLog_init(char *logfile); void swLog_put(int level, char *cnt); void swLog_free(void); #define sw_log(str,...) {snprintf(sw_error,SW_ERROR_MSG_SIZE,str,##__VA_ARGS__);swLog_put(SW_LOG_INFO, sw_error);} uint64_t swoole_hash_key(char *str, int str_len); uint32_t swoole_common_multiple(uint32_t u, uint32_t v); uint32_t swoole_common_divisor(uint32_t u, uint32_t v); static sw_inline uint16_t swoole_swap_endian16(uint16_t x) { return (((x & 0xff) << 8) | ((x & 0xff00) >> 8)); } static sw_inline uint32_t swoole_swap_endian32(uint32_t x) { return (((x & 0xff) << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | ((x & 0xff000000) >> 24)); } static sw_inline int32_t swoole_unpack(char type, void *data) { switch(type) { /*-------------------------16bit-----------------------------*/ case 'c': return *((int8_t *) data); case 'C': return *((uint8_t *) data); /*-------------------------16bit-----------------------------*/ /** * signed short (always 16 bit, machine byte order) */ case 's': return *((int16_t *) data); /** * unsigned short (always 16 bit, machine byte order) */ case 'S': return *((uint16_t *) data); /** * unsigned short (always 16 bit, big endian byte order) */ case 'n': return ntohs(*((uint16_t *) data)); /** * unsigned short (always 32 bit, little endian byte order) */ case 'v': return swoole_swap_endian16(ntohs(*((uint16_t *) data))); /*-------------------------32bit-----------------------------*/ /** * unsigned long (always 32 bit, machine byte order) */ case 'L': return *((uint32_t *) data); /** * signed long (always 32 bit, machine byte order) */ case 'l': return *((int *) data); /** * unsigned long (always 32 bit, big endian byte order) */ case 'N': return ntohl(*((uint32_t *) data)); /** * unsigned short (always 32 bit, little endian byte order) */ case 'V': return swoole_swap_endian32(ntohl(*((uint32_t *) data))); default: return *((uint32_t *) data); } } static inline char* swoole_strnstr(char *haystack, char *needle, uint32_t length) { int i; uint32_t needle_length = strlen(needle); assert(needle_length > 0); for (i = 0; i < (int) (length - needle_length + 1); i++) { if ((haystack[0] == needle[0]) && (0 == memcmp(haystack, needle, needle_length))) { return (char *) haystack; } haystack++; } return NULL; } static inline int swoole_strnpos(char *haystack, uint32_t haystack_length, char *needle, uint32_t needle_length) { assert(needle_length > 0); uint32_t i; for (i = 0; i < (int) (haystack_length - needle_length + 1); i++) { if ((haystack[0] == needle[0]) && (0 == memcmp(haystack, needle, needle_length))) { return i; } haystack++; } return -1; } static inline int swoole_strrnpos(char *haystack, char *needle, uint32_t length) { uint32_t needle_length = strlen(needle); assert(needle_length > 0); uint32_t i; haystack += (length - needle_length); for (i = length - needle_length; i > 0; i--) { if ((haystack[0] == needle[0]) && (0 == memcmp(haystack, needle, needle_length))) { return i; } haystack--; } return -1; } static inline void swoole_strtolower(char *str, int length) { char *c, *e; c = str; e = c + length; while (c < e) { *c = tolower(*c); c++; } } int swoole_itoa(char *buf, long value); void swoole_dump_bin(char *data, char type, int size); void swoole_dump_hex(char *data, int outlen); int swoole_type_size(char type); int swoole_mkdir_recursive(const char *dir); char* swoole_dirname(char *file); void swoole_dump_ascii(char *data, int size); int swoole_sync_writefile(int fd, void *data, int len); int swoole_sync_readfile(int fd, void *buf, int len); int swoole_rand(int min, int max); int swoole_system_random(int min, int max); long swoole_file_get_size(FILE *fp); int swoole_tmpfile(char *filename); swString* swoole_file_get_contents(char *filename); int swoole_file_put_contents(char *filename, char *content, size_t length); long swoole_file_size(char *filename); void swoole_open_remote_debug(void); char *swoole_dec2hex(int value, int base); int swoole_version_compare(char *version1, char *version2); #ifdef HAVE_EXECINFO void swoole_print_trace(void); #endif void swoole_ioctl_set_block(int sock, int nonblock); void swoole_fcntl_set_option(int sock, int nonblock, int cloexec); int swoole_gethostbyname(int type, char *name, char *addr); int swoole_getaddrinfo(swRequest_getaddrinfo *req); char* swoole_string_format(size_t n, const char *format, ...); //----------------------core function--------------------- int swSocket_set_timeout(int sock, double timeout); int swSocket_create_server(int type, char *address, int port, int backlog); //----------------------------------------Socket--------------------------------------- static sw_inline int swSocket_is_dgram(uint8_t type) { return (type == SW_SOCK_UDP || type == SW_SOCK_UDP6 || type == SW_SOCK_UNIX_DGRAM); } static sw_inline int swSocket_is_stream(uint8_t type) { return (type == SW_SOCK_TCP || type == SW_SOCK_TCP6 || type == SW_SOCK_UNIX_STREAM); } #ifdef SW_USE_IOCTL #define swSetNonBlock(sock) swoole_ioctl_set_block(sock, 1) #define swSetBlock(sock) swoole_ioctl_set_block(sock, 0) #else #define swSetNonBlock(sock) swoole_fcntl_set_option(sock, 1, -1) #define swSetBlock(sock) swoole_fcntl_set_option(sock, 0, -1) #endif void swoole_init(void); void swoole_clean(void); double swoole_microtime(void); void swoole_rtrim(char *str, int len); void swoole_redirect_stdout(int new_fd); int swoole_shell_exec(char *command, pid_t *pid); SW_API int swoole_add_function(const char *name, void* func); SW_API void* swoole_get_function(char *name, uint32_t length); SW_API int swoole_add_hook(enum swGlobal_hook_type type, swCallback func, int push_back); SW_API void swoole_call_hook(enum swGlobal_hook_type type, void *arg); static sw_inline uint64_t swoole_hton64(uint64_t host) { uint64_t ret = 0; uint32_t high, low; low = host & 0xFFFFFFFF; high = (host >> 32) & 0xFFFFFFFF; low = htonl(low); high = htonl(high); ret = low; ret <<= 32; ret |= high; return ret; } static sw_inline uint64_t swoole_ntoh64(uint64_t net) { uint64_t ret = 0; uint32_t high, low; low = net & 0xFFFFFFFF; high = (net >> 32) & 0xFFFFFFFF; low = ntohl(low); high = ntohl(high); ret = low; ret <<= 32; ret |= high; return ret; } int swSocket_create(int type); int swSocket_bind(int sock, int type, char *host, int *port); int swSocket_wait(int fd, int timeout_ms, int events); int swSocket_wait_multi(int *list_of_fd, int n_fd, int timeout_ms, int events); void swSocket_clean(int fd); int swSocket_sendto_blocking(int fd, void *__buf, size_t __n, int flag, struct sockaddr *__addr, socklen_t __addr_len); int swSocket_set_buffer_size(int fd, int buffer_size); int swSocket_udp_sendto(int server_sock, char *dst_ip, int dst_port, char *data, uint32_t len); int swSocket_udp_sendto6(int server_sock, char *dst_ip, int dst_port, char *data, uint32_t len); int swSocket_unix_sendto(int server_sock, char *dst_path, char *data, uint32_t len); int swSocket_sendfile_sync(int sock, char *filename, off_t offset, size_t length, double timeout); int swSocket_write_blocking(int __fd, void *__data, int __len); int swSocket_recv_blocking(int fd, void *__data, size_t __len, int flags); static sw_inline int swWaitpid(pid_t __pid, int *__stat_loc, int __options) { int ret; do { ret = waitpid(__pid, __stat_loc, __options); if (ret < 0 && errno == EINTR) { continue; } break; } while(1); return ret; } static sw_inline int swKill(pid_t __pid, int __sig) { int ret; do { ret = kill(__pid, __sig); if (ret < 0 && errno == EINTR) { continue; } break; } while (1); return ret; } #ifdef TCP_CORK #define HAVE_TCP_NOPUSH static sw_inline int swSocket_tcp_nopush(int sock, int nopush) { return setsockopt(sock, IPPROTO_TCP, TCP_CORK, (const void *) &nopush, sizeof(int)); } #else #define swSocket_tcp_nopush(sock, nopush) #endif swSignalHander swSignal_set(int sig, swSignalHander func, int restart, int mask); void swSignal_add(int signo, swSignalHander func); void swSignal_callback(int signo); void swSignal_clear(void); void swSignal_none(void); #ifdef HAVE_SIGNALFD void swSignalfd_init(); int swSignalfd_setup(swReactor *reactor); #endif typedef struct _swDefer_callback { struct _swDefer_callback *next, *prev; swCallback callback; void *data; } swDefer_callback; struct _swReactor { void *object; void *ptr; //reserve /** * last signal number */ int singal_no; uint32_t event_num; uint32_t max_event_num; uint32_t check_timer :1; uint32_t running :1; uint32_t start :1; uint32_t once :1; /** * disable accept new connection */ uint32_t disable_accept :1; uint32_t check_signalfd :1; /** * multi-thread reactor, cannot realloc sockets. */ uint32_t thread :1; /** * reactor->wait timeout (millisecond) or -1 */ int32_t timeout_msec; uint16_t id; //Reactor ID uint16_t flag; //flag uint32_t max_socket; #ifdef SW_USE_MALLOC_TRIM time_t last_malloc_trim_time; #endif #ifdef SW_USE_TIMEWHEEL swTimeWheel *timewheel; uint16_t heartbeat_interval; time_t last_heartbeat_time; #endif /** * for thread */ swConnection *socket_list; /** * for process */ swArray *socket_array; swReactor_handle handle[SW_MAX_FDTYPE]; //默认事件 swReactor_handle write_handle[SW_MAX_FDTYPE]; //扩展事件1(一般为写事件) swReactor_handle error_handle[SW_MAX_FDTYPE]; //扩展事件2(一般为错误事件,如socket关闭) int (*add)(swReactor *, int fd, int fdtype); int (*set)(swReactor *, int fd, int fdtype); int (*del)(swReactor *, int fd); int (*wait)(swReactor *, struct timeval *); void (*free)(swReactor *); int (*setHandle)(swReactor *, int fdtype, swReactor_handle); swDefer_callback *defer_callback_list; swDefer_callback idle_task; swDefer_callback future_task; void (*onTimeout)(swReactor *); void (*onFinish)(swReactor *); void (*onBegin)(swReactor *); void (*enable_accept)(swReactor *); int (*can_exit)(swReactor *); int (*write)(swReactor *, int, void *, int); int (*close)(swReactor *, int); int (*defer)(swReactor *, swCallback, void *); }; typedef struct _swWorker swWorker; typedef struct _swThread swThread; typedef struct _swProcessPool swProcessPool; struct _swWorker { /** * worker process */ pid_t pid; /** * worker thread */ pthread_t tid; swProcessPool *pool; swMemoryPool *pool_output; swMsgQueue *queue; /** * redirect stdout to pipe_master */ uint8_t redirect_stdout; /** * redirect stdin to pipe_worker */ uint8_t redirect_stdin; /** * redirect stderr to pipe_worker */ uint8_t redirect_stderr; /** * worker status, IDLE or BUSY */ uint8_t status; uint8_t type; uint8_t ipc_mode; uint8_t child_process; uint8_t traced; void (*tracer)(struct _swWorker *); /** * tasking num */ sw_atomic_t tasking_num; time_t start_time; time_t request_time; long request_count; /** * worker id */ uint32_t id; swLock lock; void *send_shm; swPipe *pipe_object; int pipe_master; int pipe_worker; int pipe; void *ptr; void *ptr2; }; typedef struct { int socket; int last_connection; char *socket_file; swString *response_buffer; } swStreamInfo; struct _swProcessPool { /** * reloading */ uint8_t reloading; uint8_t reload_init; uint8_t dispatch_mode; uint8_t ipc_mode; uint8_t started; /** * process type */ uint8_t type; /** * worker->id = start_id + i */ uint16_t start_id; /** * use message queue IPC */ uint8_t use_msgqueue; /** * use stream socket IPC */ uint8_t use_socket; char *packet_buffer; uint32_t max_packet_size; /** * message queue key */ key_t msgqueue_key; int worker_num; int max_request; int (*onTask)(struct _swProcessPool *pool, swEventData *task); void (*onWorkerStart)(struct _swProcessPool *pool, int worker_id); void (*onMessage)(struct _swProcessPool *pool, char *data, uint32_t length); void (*onWorkerStop)(struct _swProcessPool *pool, int worker_id); int (*main_loop)(struct _swProcessPool *pool, swWorker *worker); int (*onWorkerNotFound)(struct _swProcessPool *pool, pid_t pid, int status); sw_atomic_t round_id; sw_atomic_t run_worker_num; swWorker *workers; swPipe *pipes; swHashMap *map; swReactor *reactor; swMsgQueue *queue; swStreamInfo *stream; void *ptr; void *ptr2; }; //----------------------------------------Reactor--------------------------------------- static sw_inline int swReactor_error(swReactor *reactor) { switch (errno) { case EINTR: if (reactor->singal_no) { swSignal_callback(reactor->singal_no); reactor->singal_no = 0; } return SW_OK; } return SW_ERR; } static sw_inline int swReactor_event_read(int fdtype) { return (fdtype < SW_EVENT_DEAULT) || (fdtype & SW_EVENT_READ); } static sw_inline int swReactor_event_write(int fdtype) { return fdtype & SW_EVENT_WRITE; } static sw_inline int swReactor_event_error(int fdtype) { return fdtype & SW_EVENT_ERROR; } static sw_inline int swReactor_fdtype(int fdtype) { return fdtype & (~SW_EVENT_READ) & (~SW_EVENT_WRITE) & (~SW_EVENT_ERROR); } static sw_inline int swReactor_events(int fdtype) { int events = 0; if (swReactor_event_read(fdtype)) { events |= SW_EVENT_READ; } if (swReactor_event_write(fdtype)) { events |= SW_EVENT_WRITE; } if (swReactor_event_error(fdtype)) { events |= SW_EVENT_ERROR; } return events; } int swReactor_create(swReactor *reactor, int max_event); int swReactor_setHandle(swReactor *, int, swReactor_handle); int swReactor_empty(swReactor *reactor); static sw_inline swConnection* swReactor_get(swReactor *reactor, int fd) { if (reactor->thread) { return &reactor->socket_list[fd]; } swConnection *socket = (swConnection*) swArray_alloc(reactor->socket_array, fd); if (socket == NULL) { return NULL; } if (!socket->active) { socket->fd = fd; } return socket; } static sw_inline int swReactor_handle_isset(swReactor *reactor, int _fdtype) { return reactor->handle[_fdtype] != NULL; } static sw_inline void swReactor_add(swReactor *reactor, int fd, int type) { swConnection *socket = swReactor_get(reactor, fd); socket->fdtype = swReactor_fdtype(type); socket->events = swReactor_events(type); socket->removed = 0; } static sw_inline void swReactor_set(swReactor *reactor, int fd, int type) { swConnection *socket = swReactor_get(reactor, fd); socket->events = swReactor_events(type); } static sw_inline void swReactor_del(swReactor *reactor, int fd) { swConnection *socket = swReactor_get(reactor, fd); socket->events = 0; socket->removed = 1; } int swReactor_onWrite(swReactor *reactor, swEvent *ev); int swReactor_close(swReactor *reactor, int fd); int swReactor_write(swReactor *reactor, int fd, void *buf, int n); int swReactor_wait_write_buffer(swReactor *reactor, int fd); void swReactor_activate_future_task(swReactor *reactor); static sw_inline int swReactor_add_event(swReactor *reactor, int fd, enum swEvent_type event_type) { swConnection *conn = swReactor_get(reactor, fd); if (!(conn->events & event_type)) { return reactor->set(reactor, fd, conn->fdtype | conn->events | event_type); } return SW_OK; } static sw_inline int swReactor_del_event(swReactor *reactor, int fd, enum swEvent_type event_type) { swConnection *conn = swReactor_get(reactor, fd); if (conn->events & event_type) { return reactor->set(reactor, fd, conn->fdtype | (conn->events & (~event_type))); } return SW_OK; } static sw_inline int swReactor_remove_read_event(swReactor *reactor, int fd) { swConnection *conn = swReactor_get(reactor, fd); if (conn->events & SW_EVENT_WRITE) { conn->events &= (~SW_EVENT_READ); return reactor->set(reactor, fd, conn->fdtype | conn->events); } else { return reactor->del(reactor, fd); } } static sw_inline swReactor_handle swReactor_getHandle(swReactor *reactor, int event_type, int fdtype) { if (event_type == SW_EVENT_WRITE) { return (reactor->write_handle[fdtype] != NULL) ? reactor->write_handle[fdtype] : reactor->handle[SW_FD_WRITE]; } else if (event_type == SW_EVENT_ERROR) { return (reactor->error_handle[fdtype] != NULL) ? reactor->error_handle[fdtype] : reactor->handle[SW_FD_CLOSE]; } return reactor->handle[fdtype]; } int swReactorEpoll_create(swReactor *reactor, int max_event_num); int swReactorPoll_create(swReactor *reactor, int max_event_num); int swReactorKqueue_create(swReactor *reactor, int max_event_num); int swReactorSelect_create(swReactor *reactor); /*----------------------------Process Pool-------------------------------*/ int swProcessPool_create(swProcessPool *pool, int worker_num, int max_request, key_t msgqueue_key, int ipc_mode); int swProcessPool_create_unix_socket(swProcessPool *pool, char *socket_file, int blacklog); int swProcessPool_create_tcp_socket(swProcessPool *pool, char *host, int port, int blacklog); int swProcessPool_set_protocol(swProcessPool *pool, int task_protocol, uint32_t max_packet_size); int swProcessPool_wait(swProcessPool *pool); int swProcessPool_start(swProcessPool *pool); void swProcessPool_shutdown(swProcessPool *pool); pid_t swProcessPool_spawn(swProcessPool *pool, swWorker *worker); int swProcessPool_dispatch(swProcessPool *pool, swEventData *data, int *worker_id); int swProcessPool_response(swProcessPool *pool, char *data, int length); int swProcessPool_dispatch_blocking(swProcessPool *pool, swEventData *data, int *dst_worker_id); int swProcessPool_add_worker(swProcessPool *pool, swWorker *worker); int swProcessPool_del_worker(swProcessPool *pool, swWorker *worker); static sw_inline swWorker* swProcessPool_get_worker(swProcessPool *pool, int worker_id) { return &(pool->workers[worker_id - pool->start_id]); } //-----------------------------Channel--------------------------- enum SW_CHANNEL_FLAGS { SW_CHAN_LOCK = 1u << 1, SW_CHAN_NOTIFY = 1u << 2, SW_CHAN_SHM = 1u << 3, }; typedef struct _swChannel { off_t head; off_t tail; size_t size; char head_tag; char tail_tag; int num; int max_num; /** * Data length, excluding structure */ size_t bytes; int flag; int maxlen; /** * memory point */ void *mem; swLock lock; swPipe notify_fd; } swChannel; swChannel* swChannel_new(size_t size, int maxlen, int flag); #define swChannel_empty(ch) (ch->num == 0) #define swChannel_full(ch) ((ch->head == ch->tail && ch->tail_tag != ch->head_tag) || (ch->bytes + sizeof(int) * ch->num == ch->size)) int swChannel_pop(swChannel *object, void *out, int buffer_length); int swChannel_push(swChannel *object, void *in, int data_length); int swChannel_out(swChannel *object, void *out, int buffer_length); int swChannel_in(swChannel *object, void *in, int data_length); int swChannel_peek(swChannel *object, void *out, int buffer_length); int swChannel_wait(swChannel *object); int swChannel_notify(swChannel *object); void swChannel_free(swChannel *object); void swChannel_print(swChannel *); /*----------------------------LinkedList-------------------------------*/ swLinkedList* swLinkedList_new(uint8_t type, swDestructor dtor); int swLinkedList_append(swLinkedList *ll, void *data); void swLinkedList_remove_node(swLinkedList *ll, swLinkedList_node *remove_node); int swLinkedList_prepend(swLinkedList *ll, void *data); void* swLinkedList_pop(swLinkedList *ll); void* swLinkedList_shift(swLinkedList *ll); swLinkedList_node* swLinkedList_find(swLinkedList *ll, void *data); void swLinkedList_free(swLinkedList *ll); #define swLinkedList_remove(ll, data) (swLinkedList_remove_node(ll, swLinkedList_find(ll, data))) /*----------------------------Thread Pool-------------------------------*/ enum swThread_type { SW_THREAD_MASTER = 1, SW_THREAD_REACTOR = 2, SW_THREAD_WORKER = 3, SW_THREAD_UDP = 4, SW_THREAD_UNIX_DGRAM = 5, SW_THREAD_HEARTBEAT = 6, }; typedef struct _swThreadPool { swCond cond; swThread *threads; swThreadParam *params; void *ptr1; void *ptr2; #ifdef SW_THREADPOOL_USE_CHANNEL swChannel *chan; #else swRingQueue queue; #endif int thread_num; int shutdown; sw_atomic_t task_num; void (*onStart)(struct _swThreadPool *pool, int id); void (*onStop)(struct _swThreadPool *pool, int id); int (*onTask)(struct _swThreadPool *pool, void *task, int task_len); } swThreadPool; struct _swThread { pthread_t tid; int id; swThreadPool *pool; }; int swThreadPool_dispatch(swThreadPool *pool, void *task, int task_len); int swThreadPool_create(swThreadPool *pool, int max_num); int swThreadPool_run(swThreadPool *pool); int swThreadPool_free(swThreadPool *pool); //--------------------------------protocol------------------------------ int swProtocol_get_package_length(swProtocol *protocol, swConnection *conn, char *data, uint32_t size); int swProtocol_recv_check_length(swProtocol *protocol, swConnection *conn, swString *buffer); int swProtocol_recv_check_eof(swProtocol *protocol, swConnection *conn, swString *buffer); //--------------------------------timer------------------------------ typedef struct _swTimer swTimer; typedef struct _swTimer_node swTimer_node; typedef void (*swTimerCallback)(swTimer *, swTimer_node *); struct _swTimer_node { swHeap_node *heap_node; void *data; swTimerCallback callback; int64_t exec_msec; uint32_t interval; long id; int type; //0 normal node 1 node for client_coro uint8_t remove; }; enum swTimer_type { SW_TIMER_TYPE_KERNEL, SW_TIMER_TYPE_CORO, SW_TIMER_TYPE_PHP, }; struct _swTimer { /*--------------timerfd & signal timer--------------*/ swHeap *heap; swHashMap *map; int num; int use_pipe; int lasttime; int fd; long _next_id; long _current_id; long _next_msec; swPipe pipe; /*-----------------for EventTimer-------------------*/ struct timeval basetime; /*--------------------------------------------------*/ int (*set)(swTimer *timer, long exec_msec); swTimer_node* (*add)(swTimer *timer, int _msec, int persistent, void *data, swTimerCallback callback); }; int swTimer_init(long msec); int swTimer_del(swTimer *timer, swTimer_node *node); void swTimer_free(swTimer *timer); int swTimer_select(swTimer *timer); int swTimer_now(struct timeval *time); static sw_inline swTimer_node* swTimer_get(swTimer *timer, long id) { return (swTimer_node*) swHashMap_find_int(timer->map, id); } int swSystemTimer_init(int msec, int use_pipe); void swSystemTimer_signal_handler(int sig); int swSystemTimer_event_handler(swReactor *reactor, swEvent *event); swTimeWheel* swTimeWheel_new(uint16_t size); void swTimeWheel_free(swTimeWheel *tw); void swTimeWheel_forward(swTimeWheel *tw, swReactor *reactor); void swTimeWheel_add(swTimeWheel *tw, swConnection *conn); void swTimeWheel_update(swTimeWheel *tw, swConnection *conn); void swTimeWheel_remove(swTimeWheel *tw, swConnection *conn); #define swTimeWheel_new_index(tw) (tw->current == 0 ? tw->size - 1 : tw->current - 1) //-------------------------------------------------------------- //Share Memory typedef struct { swLock lock; swLock lock_2; } SwooleGS_t; //Worker process global Variable typedef struct { /** * Always run */ uint8_t run_always; /** * Current Proccess Worker's id */ uint32_t id; /** * pipe_worker */ int pipe_used; uint32_t reactor_wait_onexit :1; uint32_t reactor_init :1; uint32_t reactor_ready :1; uint32_t reactor_exit :1; uint32_t in_client :1; uint32_t shutdown :1; uint32_t wait_exit :1; int max_request; #ifdef SW_COROUTINE swLinkedList *coro_timeout_list; swLinkedList *delayed_coro_timeout_list; #endif swString **buffer_input; swString **buffer_output; swWorker *worker; } swWorkerG; typedef struct { uint16_t id; uint8_t type; uint8_t update_time; uint8_t factory_lock_target; int16_t factory_target_worker; swString **buffer_input; swString *buffer_stack; swReactor *reactor; } swThreadG; typedef struct { union { char v4[INET_ADDRSTRLEN]; char v6[INET6_ADDRSTRLEN]; } address; } swDNS_server; typedef struct _swServer swServer; typedef struct _swFactory swFactory; typedef struct { swTimer timer; uint8_t running :1; uint8_t enable_coroutine :1; uint8_t use_timerfd :1; uint8_t use_signalfd :1; uint8_t enable_signalfd :1; uint8_t reuse_port :1; uint8_t socket_dontwait :1; uint8_t dns_lookup_random :1; uint8_t use_async_resolver :1; /** * Timer used pipe */ uint8_t use_timer_pipe :1; int error; int process_type; pid_t pid; int signal_alarm; //for timer with message queue int signal_fd; int log_fd; int null_fd; int debug_fd; /** * worker(worker and task_worker) process chroot / user / group */ char *chroot; char *user; char *group; uint8_t log_level; char *log_file; int trace_flags; uint16_t cpu_num; uint32_t pagesize; uint32_t max_sockets; struct utsname uname; /** * tcp socket default buffer size */ uint32_t socket_buffer_size; swServer *serv; swFactory *factory; swMemoryPool *memory_pool; swReactor *main_reactor; char *task_tmpdir; uint16_t task_tmpdir_len; char *dns_server_v4; char *dns_server_v6; double dns_cache_refresh_time; swLock lock; swHashMap *functions; swLinkedList *hooks[SW_MAX_HOOK_TYPE]; } swServerG; extern swServerG SwooleG; //Local Global Variable extern SwooleGS_t *SwooleGS; //Share Memory Global Variable extern swWorkerG SwooleWG; //Worker Global Variable extern __thread swThreadG SwooleTG; //Thread Global Variable #define SW_CPU_NUM (SwooleG.cpu_num) //----------------------------------------------- //OS Feature #if defined(HAVE_KQUEUE) || !defined(HAVE_SENDFILE) int swoole_sendfile(int out_fd, int in_fd, off_t *offset, size_t size); #else #include #define swoole_sendfile(out_fd, in_fd, offset, limit) sendfile(out_fd, in_fd, offset, limit) #endif static sw_inline void sw_spinlock(sw_atomic_t *lock) { uint32_t i, n; while (1) { if (*lock == 0 && sw_atomic_cmp_set(lock, 0, 1)) { return; } if (SW_CPU_NUM > 1) { for (n = 1; n < SW_SPINLOCK_LOOP_N; n <<= 1) { for (i = 0; i < n; i++) { sw_atomic_cpu_pause(); } if (*lock == 0 && sw_atomic_cmp_set(lock, 0, 1)) { return; } } } swYield(); } } #ifdef __cplusplus } #endif #endif /* SWOOLE_H_ */