├── .gitignore ├── example ├── file.php └── net.php ├── composer.json ├── LICENSE ├── README.md └── src ├── EpollEvent.php ├── Epoll.php └── php.h /.gitignore: -------------------------------------------------------------------------------- 1 | /nbproject 2 | /vendor 3 | composer.lock 4 | -------------------------------------------------------------------------------- /example/file.php: -------------------------------------------------------------------------------- 1 | getFdno($fp, Epoll::RES_TYPE_FILE); 9 | $fdfp = fopen("php://fd/$fdno", 'rb'); 10 | echo fread($fdfp, 1024); -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "toknot/php-epoll", 3 | "description": "PHP bindings to the linux epoll C API.", 4 | "keywords": [ 5 | "php", 6 | "ffi", 7 | "epoll", 8 | "events", 9 | "asynchronous" 10 | ], 11 | "homepage": "http://toknot.com", 12 | "license": "BSD-3-Clause", 13 | "version": "0.2.1", 14 | "authors": [ 15 | { 16 | "name": "Szopen Xiao", 17 | "email": "xiao@toknot.com", 18 | "homepage": "http://toknot.com", 19 | "role": "Founder" 20 | } 21 | ], 22 | "support": { 23 | "issues": "https://github.com/chopins/php-epoll/issues?state=open", 24 | "source": "https://github.com/chopins/php-epoll" 25 | }, 26 | "require": { 27 | "php": ">=7.4.0", 28 | "ext-ffi": "*", 29 | "toknot/ffi-extend" : ">=0.1.5" 30 | }, 31 | "autoload": { 32 | "psr-4": { 33 | "Toknot\\": "src/" 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The php-epoll is free software. It is released under the terms of the following BSD License. 2 | 3 | Copyright © 2019 by Szopen Xiao (xiao@toknot.com) All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | Neither the name of Szopen Xiao nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /example/net.php: -------------------------------------------------------------------------------- 1 | initEvents(); 9 | $events = $epoll->initEvents(MAX_EVENTS); 10 | $stream = stream_socket_server("tcp://0.0.0.0:8000", $errno, $errstr); 11 | $listen_sock = $epoll->getFdno($stream, Epoll::RES_TYPE_NET); 12 | 13 | function perror($str) { 14 | fprintf(STDERR, $str); 15 | } 16 | 17 | $epollfd = $epoll->create(0); 18 | 19 | $ev->setEvent(Epoll::EPOLLIN); 20 | $ev->setData(['fd' => $listen_sock]); 21 | 22 | if ($epoll->ctl(Epoll::EPOLL_CTL_ADD, $listen_sock, $ev) == -1) { 23 | perror("epoll_ctl: listen_sock"); 24 | exit(EXIT_FAILURE); 25 | } 26 | 27 | for (;;) { 28 | $nfds = $epoll->wait($events, MAX_EVENTS, -1); 29 | if ($nfds == -1) { 30 | perror("epoll_wait"); 31 | exit(EXIT_FAILURE); 32 | } 33 | 34 | for ($n = 0; $n < $nfds; ++$n) { 35 | if ($events[$n]->data->fd == $listen_sock) { 36 | $conn_sock = stream_socket_accept($stream); 37 | if (!$conn_sock) { 38 | perror("accept"); 39 | exit(EXIT_FAILURE); 40 | } 41 | stream_set_blocking($conn_sock, false); 42 | $ev->setEvent(Epoll::EPOLLIN | Epoll::EPOLLET); 43 | $connFdno = $epoll->getFdno($conn_sock, Epoll::RES_TYPE_NET); 44 | $ev->setData(['fd' => $connFdno]); 45 | if ($epoll->ctl(Epoll::EPOLL_CTL_ADD, $connFdno, 46 | $ev) == -1) { 47 | perror("epoll_ctl: conn_sock"); 48 | exit(EXIT_FAILURE); 49 | } 50 | } else { 51 | do_use_fd($events[$n]->data->fd); 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # php-epoll 2 | PHP bindings to the linux epoll API. 3 | 4 | ### Requirements 5 | * PHP >= 7.4 6 | * PHP FFI extension available 7 | * Linux > 2.6 8 | * toknot/ffi-extend>=0.1 9 | 10 | ### Install 11 | use composer install: 12 | ``` 13 | composer require toknot/php-epoll 14 | 15 | ``` 16 | include composer autoload file : `./vendor/autoload.php` 17 | 18 | ## Reference 19 | 20 | * `Epoll::__construct()` 21 | * `Epoll::create(int $flags)` 22 | 23 | open an epoll file descriptor 24 | * `Epoll::ctl(int $op, int $fd, EpollEvent $events): int` 25 | 26 | control interface for an epoll file descriptor 27 | * `Epoll::wait(EpollEvent $event, int $maxevents, int $timeout, $sigmask = null): int` 28 | 29 | wait for an I/O event on an epoll file descriptor 30 | * `Epoll::getFdno(resource $file, int $type): int` 31 | 32 | get id from file descriptor of php resource 33 | * `Epoll::lastErrno(): int` 34 | 35 | get last error code 36 | * `Epoll::lastError(): string` 37 | 38 | get last error message 39 | * `Epoll::ffi(): FFI` 40 | * `Epoll::initEvents($num): EpollEvent` 41 | * `EpollEvent::__construct(Epoll $epoll,$num)` 42 | * `EpollEvent::setEvent($event, $idx)` 43 | 44 | set Epoll events 45 | * `EpollEvent::setData($data, $idx)` 46 | 47 | set user data variable 48 | * `EpollEvent::getEvents($idx): FFI\CData` 49 | 50 | 51 | 52 | ## Simple Example 53 | 54 | php resource to file descriptor 55 | ```php 56 | $epoll = new Epoll(); 57 | $fp = fopen(__FILE__, 'rb'); 58 | $fdno = $epoll->getFdno($fp, Epoll::RES_TYPE_FILE); 59 | $fdfp = fopen("php://fd/$fdno", 'rb'); 60 | echo fread($fdfp, 1024); 61 | ``` 62 | 63 | epoll example from `man epoll` 64 | 65 | ```php 66 | const MAX_EVENTS = 10; 67 | const EXIT_FAILURE = 1; 68 | 69 | $epoll = new Epoll(); 70 | $ev = $epoll->initEvents(MAX_EVENTS); 71 | $events = $epoll->initEvents(); 72 | $stream = stream_socket_server("tcp://0.0.0.0:8000", $errno, $errstr); 73 | $listen_sock = $epoll->getFdno($stream, Epoll::RES_TYPE_NET); 74 | 75 | function perror($str) { 76 | fprintf(STDERR, $str); 77 | } 78 | 79 | $epollfd = $epoll->create(0); 80 | 81 | $ev->setEvent(Epoll::EPOLLIN); 82 | $ev->setData(['fd' => $listen_sock]); 83 | 84 | if ($epoll->ctl(Epoll::EPOLL_CTL_ADD, $listen_sock, $ev) == -1) { 85 | perror("epoll_ctl: listen_sock"); 86 | exit(EXIT_FAILURE); 87 | } 88 | 89 | for (;;) { 90 | $nfds = $epoll->wait($events, MAX_EVENTS, -1); 91 | if ($nfds == -1) { 92 | perror("epoll_wait"); 93 | exit(EXIT_FAILURE); 94 | } 95 | 96 | for ($n = 0; $n < $nfds; ++$n) { 97 | if ($events[$n]->data->fd == $listen_sock) { 98 | $conn_sock = stream_socket_accept($stream); 99 | if (!$conn_sock) { 100 | perror("accept"); 101 | exit(EXIT_FAILURE); 102 | } 103 | stream_set_blocking($conn_sock, false); 104 | $ev->setEvent(Epoll::EPOLLIN | Epoll::EPOLLET); 105 | $connFdno = $epoll->getFdno($conn_sock, Epoll::RES_TYPE_NET); 106 | $ev->setData(['fd' => $connFdno]); 107 | if ($epoll->ctl(Epoll::EPOLL_CTL_ADD, $connFdno, 108 | $ev) == -1) { 109 | perror("epoll_ctl: conn_sock"); 110 | exit(EXIT_FAILURE); 111 | } 112 | } else { 113 | do_use_fd($events[$n]->data->fd); 114 | } 115 | } 116 | } 117 | ``` -------------------------------------------------------------------------------- /src/EpollEvent.php: -------------------------------------------------------------------------------- 1 | num = $num; 40 | if($num > 1) { 41 | $this->events = $epoll->ffi()->new("epoll_event[$num]"); 42 | } else { 43 | $this->events = $epoll->ffi()->new('epoll_event'); 44 | } 45 | } 46 | 47 | /** 48 | * set Epoll events 49 | * 50 | * @param int $event 51 | * @param int $idx 52 | */ 53 | public function setEvent(int $event, int $idx = 0) 54 | { 55 | if($this->num > 1) { 56 | if($idx < 0) { 57 | throw new InvalidArgumentException('EpollEvent::setEvent() of paramter 2 must be >= 0'); 58 | } 59 | $this->events[$idx]->events = $event; 60 | } else { 61 | $this->events->events = $event; 62 | } 63 | } 64 | 65 | /** 66 | * set user data variable 67 | * 68 | * @param array $data 69 | * @param int $idx 70 | */ 71 | public function setData(array $data, $idx = 0) 72 | { 73 | $keys = ['ptr', 'fd', 'u32', 'u64']; 74 | if($this->num > 1) { 75 | if($idx < 0) { 76 | throw new InvalidArgumentException('EpollEvent::setData() of paramter 2 must be >= 0'); 77 | } 78 | $ev = $this->events[$idx]; 79 | } else { 80 | $ev = $this->events; 81 | } 82 | foreach($data as $k => $v) { 83 | if(!in_array($k, $keys)) { 84 | throw new TypeError("EpollEvent::setData(): key $k is not allow"); 85 | } 86 | $ev->data->$k = $v; 87 | } 88 | } 89 | 90 | /** 91 | * get epoll struct 92 | * 93 | * @param int $idx 94 | * @return FFI\CData 95 | */ 96 | public function getEvents($idx = null): CData 97 | { 98 | if($this->num > 1 && $idx >= 0 && $idx !== null) { 99 | return $this->events[$idx]; 100 | } 101 | return $this->events; 102 | } 103 | 104 | public function offsetExists($offset): bool 105 | { 106 | return isset($this->events[$offset]); 107 | } 108 | 109 | public function offsetGet($offset) 110 | { 111 | return $this->events[$offset]; 112 | } 113 | 114 | public function offsetSet($offset, $value) 115 | { 116 | 117 | } 118 | 119 | public function offsetUnset($offset) 120 | { 121 | 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /src/Epoll.php: -------------------------------------------------------------------------------- 1 | replaceMacro('IF_PHP_DEBUG', !PHP_DEBUG, '//', $code); 69 | self::$ffi = FFI::cdef($code); 70 | } 71 | } 72 | 73 | /** 74 | * open an epoll file descriptor 75 | * 76 | * @param int $flags 77 | */ 78 | public function create(int $flags) 79 | { 80 | if($flags === 0 || $flags === self::EPOLL_CLOEXEC) { 81 | $this->epfd = self::$ffi->epoll_create1($flags); 82 | } else if($flags > 0) { 83 | $this->epfd = self::$ffi->epoll_create($flags); 84 | } else { 85 | throw new InvalidArgumentException('Epoll::create() of paramter 1 must be greater than 0'); 86 | } 87 | if($this->epfd < 0) { 88 | throw new ErrorException('create epoll file descriptor error'); 89 | } 90 | } 91 | 92 | /** 93 | * get last error code 94 | * 95 | * @return int 96 | */ 97 | public function lastErrno(): int 98 | { 99 | return self::$ffi->errno; 100 | } 101 | 102 | /** 103 | * get last error message 104 | * 105 | * @return string 106 | */ 107 | public function lastError(): string 108 | { 109 | return FFI::string(self::$ffi->strerror(self::$ffi->errno)); 110 | } 111 | 112 | /** 113 | * get current ffi instance of Epoll 114 | * 115 | * @return FFI 116 | */ 117 | public function ffi(): FFI 118 | { 119 | return self::$ffi; 120 | } 121 | 122 | /** 123 | * init epoll events 124 | * 125 | * @param int $num 126 | * @return EpollEvent 127 | */ 128 | public function initEvents(int $num = 1): EpollEvent 129 | { 130 | if($num < 1) { 131 | throw new InvalidArgumentException('Epoll::initEvents() of paramter 1 must be greater than 0'); 132 | } 133 | return new EpollEvent($this, $num); 134 | } 135 | 136 | /** 137 | * control interface for an epoll file descriptor 138 | * 139 | * @param int $op 140 | * @param int $fd 141 | * @param EpollEvent $events 142 | * @return int 143 | */ 144 | public function ctl(int $op, int $fd, EpollEvent $events): int 145 | { 146 | return self::$ffi->epoll_ctl($this->epfd, $op, $fd, FFI::addr($events->getEvents())); 147 | } 148 | 149 | /** 150 | * wait for an I/O event on an epoll file descriptor 151 | * 152 | * @param EpollEvent $event 153 | * @param int $maxevents 154 | * @param int $timeout 155 | * @param int sigmask 156 | * @return int 157 | */ 158 | public function wait(EpollEvent $event, int $maxevents, int $timeout, $sigmask = null): int 159 | { 160 | if($maxevents <= 0) { 161 | throw new InvalidArgumentException('Epoll::wait() of paramter 2 must be greater than 0'); 162 | } 163 | if($sigmask === null) { 164 | return self::$ffi->epoll_wait($this->epfd, $event->getEvents(), $maxevents, $timeout); 165 | } else { 166 | return self::$ffi->epoll_pwait($this->epfd, $event->getEvents(), $maxevents, $timeout, $sigmask); 167 | } 168 | } 169 | 170 | /** 171 | * get id from file descriptor of php resource 172 | * 173 | * @param mix $resource php resource 174 | * @param int $type resource type, 175 | * value is Epoll::RES_TYPE_FILE: open file resource, like fopen,STDOUT 176 | * Epoll::RES_TYPE_NET: open network resource, like stream_socket_server 177 | * @return int if error return -1, otherwise return greater then 0 178 | */ 179 | public function getFdno($resource, $type): int 180 | { 181 | if(!is_resource($resource)) { 182 | throw new TypeError('Epoll::getFdno() of paramter 1 must be resource'); 183 | } 184 | 185 | $stream = self::$phpExt->zval($resource)->ptr; 186 | $fd = self::$ffi->cast('php_stream', $stream)->abstract; 187 | if($type === self::RES_TYPE_FILE) { 188 | return self::$ffi->cast('php_stdio_stream_data', $fd)->fd; 189 | } elseif($type === self::RES_TYPE_NET) { 190 | return self::$ffi->cast('php_netstream_data_t', $fd)->socket; 191 | } else { 192 | return -1; 193 | } 194 | } 195 | 196 | } 197 | -------------------------------------------------------------------------------- /src/php.h: -------------------------------------------------------------------------------- 1 | typedef uint64_t zend_ulong; 2 | typedef int64_t zend_long; 3 | typedef int64_t zend_off_t; 4 | typedef unsigned long sigset_t; 5 | 6 | typedef struct _zend_object_handlers zend_object_handlers; 7 | typedef unsigned char zend_uchar; 8 | typedef struct _zend_array zend_array; 9 | typedef struct _zend_object zend_object; 10 | typedef struct _zend_resource zend_resource; 11 | typedef struct _zend_reference zend_reference; 12 | typedef struct _zval_struct zval; 13 | typedef struct _zend_ast_ref zend_ast_ref; 14 | typedef struct _zend_ast zend_ast; 15 | typedef struct _zend_class_entry zend_class_entry; 16 | typedef union _zend_function zend_function; 17 | typedef struct _zend_array HashTable; 18 | typedef struct _php_netstream_data_t php_netstream_data_t; 19 | typedef void (*dtor_func_t)(zval *pDest); 20 | 21 | typedef struct _php_stream php_stream; 22 | 23 | typedef struct _zend_refcounted_h { 24 | uint32_t refcount; /* reference counter 32-bit */ 25 | union { 26 | uint32_t type_info; 27 | } u; 28 | } zend_refcounted_h; 29 | typedef struct _zend_string { 30 | zend_refcounted_h gc; 31 | zend_ulong h; /* hash value */ 32 | size_t len; 33 | char val[1]; 34 | } zend_string; 35 | typedef struct _zend_refcounted { 36 | zend_refcounted_h gc; 37 | } zend_refcounted; 38 | struct _zend_resource { 39 | zend_refcounted_h gc; 40 | int handle; // TODO: may be removed ??? 41 | int type; 42 | void *ptr; 43 | }; 44 | typedef struct _zend_property_info zend_property_info; 45 | 46 | typedef union { 47 | zend_property_info *ptr; 48 | uintptr_t list; 49 | } zend_property_info_source_list; 50 | 51 | 52 | struct _zval_struct { 53 | union { 54 | zend_long lval; /* long value */ 55 | double dval; /* double value */ 56 | zend_refcounted *counted; 57 | zend_string *str; 58 | zend_array *arr; 59 | zend_object *obj; 60 | zend_resource *res; 61 | zend_reference *ref; 62 | zend_ast_ref *ast; 63 | zval *zv; 64 | void *ptr; 65 | zend_class_entry *ce; 66 | zend_function *func; 67 | struct { 68 | uint32_t w1; 69 | uint32_t w2; 70 | } ww; 71 | } value; 72 | union { 73 | struct { 74 | zend_uchar type; /* active type */ 75 | zend_uchar type_flags; 76 | zend_uchar const_flags; 77 | zend_uchar reserved; /* call info for EX(This) */ 78 | } v; 79 | uint32_t type_info; 80 | } u1; 81 | union { 82 | uint32_t var_flags; 83 | uint32_t next; /* hash collision chain */ 84 | uint32_t cache_slot; /* literal cache slot */ 85 | uint32_t lineno; /* line number (for ast nodes) */ 86 | uint32_t num_args; /* arguments number for EX(This) */ 87 | uint32_t fe_pos; /* foreach position */ 88 | uint32_t fe_iter_idx; /* foreach iterator index */ 89 | } u2; 90 | }; 91 | struct _zend_ast_ref { 92 | zend_refcounted_h gc; 93 | /*zend_ast ast; zend_ast follows the zend_ast_ref structure */ 94 | }; 95 | struct _zend_reference { 96 | zend_refcounted_h gc; 97 | zval val; 98 | zend_property_info_source_list sources; 99 | }; 100 | struct _zend_object { 101 | zend_refcounted_h gc; 102 | uint32_t handle; // TODO: may be removed ??? 103 | zend_class_entry *ce; 104 | const zend_object_handlers *handlers; 105 | HashTable *properties; 106 | zval properties_table[1]; 107 | }; 108 | typedef struct _Bucket { 109 | zval val; 110 | zend_ulong h; /* hash value (or numeric index) */ 111 | zend_string *key; /* string key or NULL for numerics */ 112 | } Bucket; 113 | 114 | typedef struct _zend_array { 115 | zend_refcounted_h gc; 116 | union { 117 | struct { 118 | zend_uchar flags; 119 | zend_uchar _unused; 120 | zend_uchar nIteratorsCount; 121 | zend_uchar _unused2; 122 | } v; 123 | uint32_t flags; 124 | } u; 125 | uint32_t nTableMask; 126 | Bucket *arData; 127 | uint32_t nNumUsed; 128 | uint32_t nNumOfElements; 129 | uint32_t nTableSize; 130 | uint32_t nInternalPointer; 131 | zend_long nNextFreeElement; 132 | dtor_func_t pDestructor; 133 | }; 134 | 135 | typedef struct _php_stream_filter_chain { 136 | void *head, *tail; 137 | 138 | /* Owning stream */ 139 | php_stream *stream; 140 | } php_stream_filter_chain; 141 | 142 | struct _php_stream { 143 | void *ops; 144 | void *abstract; /* convenience pointer for abstraction */ 145 | 146 | php_stream_filter_chain readfilters, writefilters; 147 | 148 | void *wrapper; /* which wrapper was used to open the stream */ 149 | void *wrapperthis; /* convenience pointer for a instance of a wrapper */ 150 | zval wrapperdata; /* fgetwrapperdata retrieves this */ 151 | 152 | uint8_t is_persistent:1; 153 | uint8_t in_free:2; /* to prevent recursion during free */ 154 | uint8_t eof:1; 155 | uint8_t __exposed:1; /* non-zero if exposed as a zval somewhere */ 156 | 157 | /* so we know how to clean it up correctly. This should be set to 158 | * PHP_STREAM_FCLOSE_XXX as appropriate */ 159 | uint8_t fclose_stdiocast:2; 160 | 161 | uint8_t fgetss_state; /* for fgetss to handle multiline tags */ 162 | 163 | char mode[16]; /* "rwb" etc. ala stdio */ 164 | 165 | uint32_t flags; /* PHP_STREAM_FLAG_XXX */ 166 | 167 | zend_resource *res; /* used for auto-cleanup */ 168 | void *stdiocast; /* cache this, otherwise we might leak! */ 169 | char *orig_path; 170 | 171 | zend_resource *ctx; 172 | 173 | /* buffer */ 174 | zend_off_t position; /* of underlying stream */ 175 | unsigned char *readbuf; 176 | size_t readbuflen; 177 | zend_off_t readpos; 178 | zend_off_t writepos; 179 | 180 | /* how much data to read when filling buffer */ 181 | size_t chunk_size; 182 | 183 | IF_PHP_DEBUG const char *open_filename;uint32_t open_lineno; 184 | 185 | struct _php_stream *enclosing_stream; /* this is a private stream owned by enclosing_stream */ 186 | }; /* php_stream */ 187 | 188 | typedef struct { 189 | void *file; 190 | int fd; /* underlying file descriptor */ 191 | unsigned is_process_pipe:1; /* use pclose instead of fclose */ 192 | unsigned is_pipe:1; /* don't try and seek */ 193 | unsigned cached_fstat:1; /* sb is valid */ 194 | unsigned is_pipe_blocking:1; /* allow blocking read() on pipes, currently Windows only */ 195 | unsigned no_forced_fstat:1; /* Use fstat cache even if forced */ 196 | unsigned _reserved:28; 197 | 198 | int lock_flag; /* stores the lock state */ 199 | zend_string *temp_name; /* if non-null, this is the path to a temporary file that 200 | * is to be deleted when the stream is closed */ 201 | char last_op; 202 | char *last_mapped_addr; 203 | size_t last_mapped_len; 204 | 205 | void * sb; 206 | } php_stdio_stream_data; 207 | 208 | struct _php_netstream_data_t { 209 | int socket; 210 | char is_blocked; 211 | void* timeout; 212 | char timeout_event; 213 | size_t ownsize; 214 | } ; 215 | 216 | typedef union epoll_data { 217 | void *ptr; 218 | int fd; 219 | uint32_t u32; 220 | uint64_t u64; 221 | } epoll_data_t; 222 | 223 | typedef struct epoll_event { 224 | uint32_t events; /* Epoll events */ 225 | epoll_data_t data; /* User data variable */ 226 | } epoll_event; 227 | int epoll_create(int size); 228 | int epoll_create1 (int __flags); 229 | int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); 230 | int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout); 231 | int epoll_pwait(int epfd, struct epoll_event *events,int maxevents, int timeout,const sigset_t *sigmask); 232 | 233 | int errno; 234 | char *strerror(int errno); 235 | 236 | zend_array *zend_rebuild_symbol_table(void); 237 | HashTable* zend_array_dup(HashTable *source); 238 | --------------------------------------------------------------------------------