前面我们分析过了队列的创建过程,这里我们看下队列的push流程,其push调用形式如下。
bool swoole_process->push(string $data);
下面我们看下底层实现。
static PHP_METHOD(swoole_process, push)
{
char *data;
zend_size_t length;
//message的封装
struct
{
long type;
char data[SW_MSGMAX];
} message;
//解析输入参数信息,这里输入只包括要发送的数据本身
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &length) == FAILURE)
{
RETURN_FALSE;
}
if (length <= 0)//要发送的数据长度异常
{
swoole_php_fatal_error(E_WARNING, "the data to push is empty.");
RETURN_FALSE;
}
else if (length >= sizeof(message.data))//数据长度不能超过SW_MSGMAX,也就是64KB
{
swoole_php_fatal_error(E_WARNING, "the data to push is too big.");
RETURN_FALSE;
}
swWorker *process = swoole_get_object(getThis());//获取swoole内部封装的对象信息
if (!process->queue) //未创建队列,这种情况是由于调用顺序造成的
{
swoole_php_fatal_error(E_WARNING, "no msgqueue, can not use push()");
RETURN_FALSE;
}
message.type = process->id;//message的type赋值为process的ID信息,也就是进程ID信息
memcpy(message.data, data, length);
//push数据
if (swMsgQueue_push(process->queue, (swQueue_data *)&message, length) < 0)
{
RETURN_FALSE;
}
RETURN_TRUE;
}
int swMsgQueue_push(swMsgQueue *q, swQueue_data *in, int length)
{
int ret;
while (1)
{
ret = msgsnd(q->msg_id, in, length, q->flags);//调用linux系统调用进行消息的发送,这里不存在部分消息写入的情况
if (ret < 0)//写入失败
{
SwooleG.error = errno;
if (errno == EINTR)//系统调用被信号中断,继续发送
{
continue;
}
else if (errno == EAGAIN)//队列为非阻塞的,这里支持返回,不做尝试
{
return -1;
}
else
{
swSysError("msgsnd(%d, %d, %ld) failed.", q->msg_id, length, in->mtype);
return -1;
}
}
else
{
return ret;
}
}
return 0;
}