swoole_process源码读解-构造析构函数
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;
}
//当前是否server中的master进程中
if (SwooleG.serv && SwooleGS->start == 1 && swIsMaster())
{
swoole_php_fatal_error(E_ERROR, "swoole_process can't be used in master process.");
RETURN_FALSE;
}
//解析参数,具体的请查看swoole官方手册中各参数含义
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);
//分配process所需的内存
swWorker *process = emalloc(sizeof(swWorker));
bzero(process, sizeof(swWorker));
int base = 1;
//计算当前已启动process数量
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,注意这里不是进程pid
process->id = php_swoole_worker_round_id++;
//输出重定向
if (redirect_stdin_and_stdout)
{
process->redirect_stdin = 1;
process->redirect_stdout = 1;
process->redirect_stderr = 1;
/**
* Forced to use stream pipe
*/
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;
//设置process对象的pipe属性
zend_update_property_long(swoole_process_class_entry_ptr, getThis(), ZEND_STRL("pipe"), process->pipe_master TSRMLS_CC);
}
//将当前对象加入到swoole全局的对象管理当中
swoole_set_object(getThis(), process);
//设置process对象的callback属性
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);
//是否需要为swoole_objects重新分配内存
if (handle >= swoole_objects.size)
{
uint32_t old_size = swoole_objects.size;
//新swoole_objects大小
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; //zend_types.h:84
typedef struct _zend_object zend_object; //zend_types.h:89
struct _zend_object { //zend_types.h:277
zend_refcounted_h gc;
uint32_t handle; // TODO: may be removed ???
zend_class_entry *ce;
const zend_object_handlers *handlers;
HashTable *properties;
zval properties_table[1];
};
typedef union _zend_value { //zend_types.h:101
zend_long lval; /* long value */
double dval; /* double value */
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_types.h:121
zend_value value; /* value */
union {
struct {
ZEND_ENDIAN_LOHI_4(
zend_uchar type, /* active type */
zend_uchar type_flags,
zend_uchar const_flags,
zend_uchar reserved) /* call info for EX(This) */
} v;
uint32_t type_info;
} u1;
union {
uint32_t next; /* hash collision chain */
uint32_t cache_slot; /* literal cache slot */
uint32_t lineno; /* line number (for ast nodes) */
uint32_t num_args; /* arguments number for EX(This) */
uint32_t fe_pos; /* foreach position */
uint32_t fe_iter_idx; /* foreach iterator index */
uint32_t access_flags; /* class constant access flags */
uint32_t property_guard; /* single property guard */
uint32_t extra; /* not further specified */
} 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);
}
析构函数主要判断是否使用管道和队列,然后关闭管道和释放管道队列占用的内存,然后释放进程占用内存。
近期评论