php源码对大部分php程序员来说都是神秘的,因为php本身是一门神奇伟大的语音。它可以让没有什么编程基础的人可以编程,而且偏向于应用。而swoole是php中一个非常不错的扩展,它让php对异步编程更容易,对高并发做了很多的支持。而我想抽时间写一个针对swoole源码解读的文章,来让我们更深入的了解理解swoole,更好的在项目中使用它。
适合人群
那么这个系列文章比较适合哪些程序员哪?对php扩展开发有一定了解,有c/c++语言功底的。如果你对php扩展开发不是很了解,可以查看一下我以前写过php扩展开发的文章,或者看一下《PHP扩展开发及内核应用》这本书。
源码版本
php版本:7.1.11
swoole版本:2.1.2
下面将进入正题,我们将一起来查看swoole_process是如何实现的。
swoole_process构造函数
构造函数源码实现在swoole_process.c:239
static PHP_METHOD(swoole_process, __construct)
{
zend_bool redirect_stdin_and_stdout = 0;
long pipe_type = 2;
zval *callback;
if (!SWOOLE_G(cli))
{
swoole_php_fatal_error(E_ERROR, "swoole_process only can be used in PHP CLI mode.");
RETURN_FALSE;
}
if (SwooleG.serv && SwooleGS->start == 1 && swIsMaster())
{
swoole_php_fatal_error(E_ERROR, "swoole_process can't be used in master process.");
RETURN_FALSE;
}
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|bl", &callback, &redirect_stdin_and_stdout, &pipe_type) == FAILURE)
{
RETURN_FALSE;
}
char *func_name = NULL;
if (!sw_zend_is_callable(callback, 0, &func_name TSRMLS_CC))
{
swoole_php_fatal_error(E_ERROR, "function '%s' is not callable", func_name);
efree(func_name);
RETURN_FALSE;
}
efree(func_name);
swWorker *process = emalloc(sizeof(swWorker));
bzero(process, sizeof(swWorker));
int base = 1;
if (SwooleG.serv && SwooleGS->start)
{
base = SwooleG.serv->worker_num + SwooleG.task_worker_num + SwooleG.serv->user_worker_num;
}
if (php_swoole_worker_round_id == 0)
{
php_swoole_worker_round_id = base;
}
process->id = php_swoole_worker_round_id++;
if (redirect_stdin_and_stdout)
{
process->redirect_stdin = 1;
process->redirect_stdout = 1;
process->redirect_stderr = 1;
pipe_type = 1;
}
if (pipe_type > 0)
{
swPipe *_pipe = emalloc(sizeof(swWorker));
int socket_type = pipe_type == 1 ? SOCK_STREAM : SOCK_DGRAM;
if (swPipeUnsock_create(_pipe, 1, socket_type) < 0)
{
RETURN_FALSE;
}
process->pipe_object = _pipe;
process->pipe_master = _pipe->getFd(_pipe, SW_PIPE_MASTER);
process->pipe_worker = _pipe->getFd(_pipe, SW_PIPE_WORKER);
process->pipe = process->pipe_master;
zend_update_property_long(swoole_process_class_entry_ptr, getThis(), ZEND_STRL("pipe"), process->pipe_master TSRMLS_CC);
}
swoole_set_object(getThis(), process);
zend_update_property(swoole_process_class_entry_ptr, getThis(), ZEND_STRL("callback"), callback TSRMLS_CC);
}
这里面有调用swoole_set_object函数,getThis函数获得当前对象指针,可以理解为php中常用的$this关键字,下面我们看一下swoole_set_object是如何实现的。
swoole_set_object在swoole.c:699
void swoole_set_object(zval *object, void *ptr)
{
SWOOLE_GET_TSRMLS;
int handle = sw_get_object_handle(object);
assert(handle < SWOOLE_OBJECT_MAX);
if (handle >= swoole_objects.size)
{
uint32_t old_size = swoole_objects.size;
uint32_t new_size = swoole_get_new_size(old_size, handle TSRMLS_CC);
void *old_ptr = swoole_objects.array;
void *new_ptr = NULL;
new_ptr = realloc(old_ptr, sizeof(void*) * new_size);
if (!new_ptr)
{
swoole_php_fatal_error(E_ERROR, "malloc(%d) failed.", (int )(new_size * sizeof(void *)));
return;
}
bzero(new_ptr + (old_size * sizeof(void*)), (new_size - old_size) * sizeof(void*));
swoole_objects.array = new_ptr;
swoole_objects.size = new_size;
}
swoole_objects.array[handle] = ptr;
}
sw_get_object_handle是1个宏函数,最终展开结果是((*(object)).value.obj)->handle。其作用是获得当前对象的handle,也就是它的索引。
typedef struct _zval_struct zval;
typedef struct _zend_object zend_object;
struct _zend_object {
zend_refcounted_h gc;
uint32_t handle;
zend_class_entry *ce;
const zend_object_handlers *handlers;
HashTable *properties;
zval properties_table[1];
};
typedef union _zend_value {
zend_long lval;
double dval;
zend_refcounted *counted;
zend_string *str;
zend_array *arr;
zend_object *obj;
zend_resource *res;
zend_reference *ref;
zend_ast_ref *ast;
zval *zv;
void *ptr;
zend_class_entry *ce;
zend_function *func;
struct {
uint32_t w1;
uint32_t w2;
} ww;
} zend_value;
struct _zval_struct {
zend_value value;
union {
struct {
ZEND_ENDIAN_LOHI_4(
zend_uchar type,
zend_uchar type_flags,
zend_uchar const_flags,
zend_uchar reserved)
} v;
uint32_t type_info;
} u1;
union {
uint32_t next;
uint32_t cache_slot;
uint32_t lineno;
uint32_t num_args;
uint32_t fe_pos;
uint32_t fe_iter_idx;
uint32_t access_flags;
uint32_t property_guard;
uint32_t extra;
} u2;
};
#define sw_get_object_handle(object) Z_OBJ_HANDLE_P(object)
#define Z_OBJ_HANDLE_P(zval_p) Z_OBJ_HANDLE(*(zval_p))
#define Z_OBJ_HANDLE(zval) (Z_OBJ((zval)))->handle
#define Z_OBJ(zval) (zval).value.obj
析构函数
析构函数实现在swoole_process.c:318
static PHP_METHOD(swoole_process, __destruct)
{
swWorker *process = swoole_get_object(getThis());
swPipe *_pipe = process->pipe_object;
if (_pipe)
{
_pipe->close(_pipe);
efree(_pipe);
}
if (process->queue)
{
efree(process->queue);
}
efree(process);
}
析构函数主要判断是否使用管道和队列,然后关闭管道和释放管道队列占用的内存,然后释放进程占用内存。
近期评论