This repository has been archived on 2018-04-01. You can view files and clone it, but cannot push or open issues or pull requests.
php-asio/src/common.hpp

198 lines
6.3 KiB
C++
Raw Permalink Normal View History

2018-04-01 08:35:05 +00:00
/**
* php-asio/common.hpp
*
* @author CismonX<admin@cismon.net>
*/
#pragma once
#include "p3.hpp"
#include <boost/asio.hpp>
#include <boost/bind.hpp>
// Compatible with PHP 7.3
#if PHP_VERSION_ID < 70300
#define GC_ADDREF(p) ++GC_REFCOUNT(p)
#define GC_DELREF(p) --GC_REFCOUNT(p)
#endif
#if PHP_VERSION_ID < 70115 || (PHP_VERSION_ID > 70200 && PHP_VERSION_ID < 70203)
#if PHP_VERSION_ID < 70100
#define _zend_wrong_parameters_count_error(throw, ...) zend_wrong_paramers_count_error(__VA_ARGS__)
#elif PHP_VERSION_ID < 70200
#define _zend_wrong_parameters_count_error(throw, ...) zend_wrong_parameters_count_error(__VA_ARGS__)
#else
#define _zend_wrong_parameters_count_error(...) zend_wrong_parameters_count_error(__VA_ARGS__)
#endif
// See https://externals.io/message/101364 for details.
#undef ZEND_PARSE_PARAMETERS_START_EX
#define ZEND_PARSE_PARAMETERS_START_EX(flags, min_num_args, max_num_args) do { \
const int _flags = (flags); \
int _min_num_args = (min_num_args); \
int _max_num_args = (max_num_args); \
int _num_args = EX_NUM_ARGS(); \
int _i; \
zval *_real_arg, *_arg = NULL; \
zend_expected_type _expected_type = Z_EXPECTED_LONG; \
char *_error = NULL; \
zend_bool _dummy; \
zend_bool _optional = 0; \
int error_code = ZPP_ERROR_OK; \
((void)_i); \
((void)_real_arg); \
((void)_arg); \
((void)_expected_type); \
((void)_error); \
((void)_dummy); \
((void)_optional); \
do { \
if (UNEXPECTED(_num_args < _min_num_args) || \
(UNEXPECTED(_num_args > _max_num_args) && \
EXPECTED(_max_num_args >= 0))) { \
if (!(_flags & ZEND_PARSE_PARAMS_QUIET)) { \
_zend_wrong_parameters_count_error(_flags & ZEND_PARSE_PARAMS_THROW, \
_num_args, _min_num_args, _max_num_args); \
} \
error_code = ZPP_ERROR_FAILURE; \
break; \
} \
_i = 0; \
_real_arg = ZEND_CALL_ARG(execute_data, 0);
#endif
#define PHP_ASIO_OBJ_ALLOC(obj, type, arg) \
auto obj = p3::alloc_object<type>(type::class_entry, [this](type* ptr) { \
new(ptr) type(arg); \
})
#define PHP_ASIO_OBJ_DTOR(obj) GC_DELREF(p3::to_zend_object(obj))
#define ZVAL_ALLOC(name) name = static_cast<zval*>(emalloc(sizeof(zval)))
#define ZVAL_PTR_INIT(name) auto ZVAL_ALLOC(name)
#define ZVAL_INIT(name) zval name = {{ 0 }}
#define RETVAL_EC(ec) RETVAL_LONG(static_cast<zend_long>((ec).value()))
#define PHP_ASIO_ERROR(type, msg) php_error_docref(nullptr, type, msg)
#define PHP_ASIO_CE_DECLARE() \
static zend_class_entry* class_entry; \
static zend_object_handlers handlers
#define PHP_ASIO_CE_DEFINE(type) \
zend_class_entry* type::class_entry; \
zend_object_handlers type::handlers
// Handlers with one argument is treated as ones with two arguments.
#define NOARG int
#define ASYNC_HANDLER_SINGLE_ARG \
std::function<void(const boost::system::error_code&)>(boost::bind( \
&future::resolve<std::remove_pointer_t<decltype(this)>, NOARG>, \
future, boost::asio::placeholders::error, 0))
#define ASYNC_HANDLER_DOUBLE_ARG(obj_type) \
std::function<void(const boost::system::error_code&, obj_type)>(boost::bind( \
&future::resolve<std::remove_pointer_t<decltype(this)>, obj_type>, \
future, boost::asio::placeholders::error, _2))
// If you don't need coroutines, you can turn it off for better performance.
#ifdef ENABLE_COROUTINE
#define CORO_REGISTER(value) future::coroutine(value)
#define FUTURE_INIT() \
zend_object* obj; \
auto future = future::add(this, obj);
#define FUTURE_RETURN() RETVAL_OBJ(obj)
#define INIT_RETVAL() \
ZVAL_PTR_INIT(retval); \
ZVAL_NULL(retval)
#define PASS_RETVAL retval
#else
#define CORO_REGISTER(value)
#define FUTURE_INIT() auto future = future::add(this)
#define FUTURE_RETURN()
#define INIT_RETVAL() ZVAL_INIT(retval)
#define PASS_RETVAL &retval
#endif // ENABLE_COROUTINE
#define CORO_RETURN_NULL() \
ZVAL_PTR_INIT(retval); \
ZVAL_NULL(retval); \
return retval
#define CORO_RETURN(type, value) \
ZVAL_PTR_INIT(retval); \
type(retval, value); \
return retval
// If you don't need multi-threading support for I/O objects, you can disable Strand for better performance.
#if defined(ENABLE_STRAND) && !defined(ZTS)
#undef ENABLE_STRAND
#endif
#ifdef ENABLE_STRAND
#define STRAND_UNWRAP() \
callback = future->handle_strand(callback); \
if (future->get_strand()) \
ZVAL_COPY_VALUE(cb, callback); \
else
#define STRAND_RESOLVE(arg) future->get_strand() ? future->get_strand()->wrap(arg) : arg
#else
#define STRAND_UNWRAP()
#define STRAND_RESOLVE(arg) arg
#endif // ENABLE_STRAND
#define PHP_ASIO_INVOKE_CALLBACK_START(argc) \
const auto _argc = argc; \
if (callback && zend_is_callable(callback, 0, nullptr)) { \
zval arguments[_argc] = {{{ 0 }}}; \
ZVAL_OBJ(&arguments[0], p3::to_zend_object(this));
#define PHP_ASIO_INVOKE_CALLBACK() \
ZVAL_LONG(&arguments[_argc - 2], static_cast<zend_long>(error.value())); \
if (argument) \
ZVAL_COPY(&arguments[_argc - 1], argument); \
else \
ZVAL_NULL(&arguments[_argc - 1]); \
INIT_RETVAL(); \
call_user_function(CG(function_table), nullptr, callback, PASS_RETVAL, _argc, arguments)
#define PHP_ASIO_INVOKE_CALLBACK_END() \
CORO_REGISTER(retval); \
zval_ptr_dtor(callback); \
efree(callback); \
} \
if (argument) { \
zval_ptr_dtor(argument); \
efree(argument); \
}
#define PHP_ASIO_INC_HANDLER_COUNT() \
if (handler_count_inc() == 1) \
GC_ADDREF(p3::to_zend_object(this))
#define PHP_ASIO_DEC_HANDLER_COUNT() \
if (handler_count_dec() == 0) \
PHP_ASIO_OBJ_DTOR(this)
// To ensure the callback and the extra arg is still alive when async operation resolves,
// We shall allocate new memory on the heap.
#define PHP_ASIO_FUTURE_INIT() \
PHP_ASIO_INC_HANDLER_COUNT(); \
FUTURE_INIT(); \
zval* cb = nullptr; \
if (callback) { \
ZVAL_ALLOC(cb); \
STRAND_UNWRAP() \
ZVAL_COPY(cb, callback); \
} \
zval* args = nullptr; \
if (argument) { \
ZVAL_ALLOC(args); \
ZVAL_COPY(args, argument); \
}
using boost::asio::ip::tcp;
using boost::asio::ip::udp;
using unix = boost::asio::local::stream_protocol;
using udg = boost::asio::local::datagram_protocol;