1.在red_dispatcher_init()中要创建 red_worker线程 下面是red_worker_main()线程运行的函数
SPICE_GNUC_NORETURN void *red_worker_main(void *arg) //这里的arg其实就是 在red_dispatcher_init()中的init_data结构
{
RedWorker *worker = spice_malloc(sizeof(RedWorker)); //创建worker 并分配内存
spice_info("begin"); //打印调试和错误信息
spice_assert(MAX_PIPE_SIZE > WIDE_CLIENT_ACK_WINDOW &&
MAX_PIPE_SIZE > NARROW_CLIENT_ACK_WINDOW); //ensure wakeup by ack message
#if defined(RED_WORKER_STAT) || defined(COMPRESS_STAT)
if (pthread_getcpuclockid(pthread_self(), &clock_id)) {
spice_error("pthread_getcpuclockid failed");
}
#endif
red_init(worker, (WorkerInitData *)arg); //内容挺多,后面单独分析
red_init_quic(worker); // 图像压缩初始化的,初始化worker中的quic_data成员
red_init_lz(worker); //图像压缩初始化的,初始化worker中的lz_data成员
red_init_jpeg(worker); //图像压缩初始化的,初始化worker中的jpeg_data成员
red_init_zlib(worker); //图像压缩初始化的,初始化worker中的zlib_data成员
worker->event_timeout = INF_EVENT_WAIT;// 超时时间设置
for (;;) { //这个for循环主要用于对超时和poll机制轮训的处理,并且真正做显示和视频图像处理的也就在这个循环中了
int i, num_events;
unsigned int timers_queue_timeout;
timers_queue_timeout = spice_timer_queue_get_timeout_ms();
worker->event_timeout = MIN(red_get_streams_timout(worker), worker->event_timeout);
worker->event_timeout = MIN(timers_queue_timeout, worker->event_timeout);
num_events = poll(worker->poll_fds, MAX_EVENT_SOURCES, worker->event_timeout);
red_handle_streams_timout(worker);
spice_timer_queue_cb();
if (worker->display_channel) {
/* during migration, in the dest, the display channel can be initialized
while the global lz data not since migrate data msg hasn't been
received yet */
red_channel_apply_clients(&worker->display_channel->common.base,
red_display_cc_free_glz_drawables);
}
worker->event_timeout = INF_EVENT_WAIT;
if (num_events == -1) {
if (errno != EINTR) {
spice_error("poll failed, %s", strerror(errno));
}
}
for (i = 0; i < MAX_EVENT_SOURCES; i++) {
/* The watch may have been removed by the watch-func from
another fd (ie a disconnect through the dispatcher),
in this case watch_func is NULL. */
if (worker->poll_fds[i].revents && worker->watches[i].watch_func) {
int events = 0;
if (worker->poll_fds[i].revents & POLLIN) {
events |= SPICE_WATCH_EVENT_READ;
}
if (worker->poll_fds[i].revents & POLLOUT) {
events |= SPICE_WATCH_EVENT_WRITE;
}
worker->watches[i].watch_func(worker->poll_fds[i].fd, events,
worker->watches[i].watch_func_opaque);
}
}
/* Clear the poll_fd for any removed watches, see the comment in
watch_remove for why we don't do this there. */
for (i = 0; i < MAX_EVENT_SOURCES; i++) {
if (!worker->watches[i].watch_func) {
worker->poll_fds[i].fd = -1;
}
}
if (worker->running) {
int ring_is_empty;
red_process_cursor(worker, MAX_PIPE_SIZE, &ring_is_empty);//处理光标
red_process_commands(worker, MAX_PIPE_SIZE, &ring_is_empty);//处理显示命令
}
red_push(worker);//往客户端推送显示的数据和视频
}
abort();
}
2.red_worker_main()中的 red_init()函数分析
static void red_init(RedWorker *worker, WorkerInitData *init_data)
{
RedWorkerMessage message; //定义一个信息 message
Dispatcher *dispatcher; // 定义一个dispatcher
int i;
spice_assert(sizeof(CursorItem) <= QXL_CURSUR_DEVICE_DATA_SIZE);
memset(worker, 0, sizeof(RedWorker)); // 把RedWorker清零
dispatcher = red_dispatcher_get_dispatcher(init_data->red_dispatcher);// 把init_data带过来的信息全部取过来,赋给worker成员
dispatcher_set_opaque(dispatcher, worker); //dispatcher的opaque指针指向worker
worker->red_dispatcher = init_data->red_dispatcher;
worker->qxl = init_data->qxl;
worker->id = init_data->id;
worker->channel = dispatcher_get_recv_fd(dispatcher);
register_callbacks(dispatcher);
worker->pending = init_data->pending;
worker->cursor_visible = TRUE;
spice_assert(init_data->num_renderers > 0);
worker->num_renderers = init_data->num_renderers;
memcpy(worker->renderers, init_data->renderers, sizeof(worker->renderers));//上面是把init_data信息赋给RedWorker
worker->renderer = RED_RENDERER_INVALID; //渲染
worker->mouse_mode = SPICE_MOUSE_MODE_SERVER;//鼠标模式设置为服务器模式
worker->image_compression = init_data->image_compression;//下面是图像压缩的设置
worker->jpeg_state = init_data->jpeg_state;
worker->zlib_glz_state = init_data->zlib_glz_state;
worker->streaming_video = init_data->streaming_video; //视频压缩的设置,上面是图像压缩的设置
worker->driver_cap_monitors_config = 0; //驱动器配置参数
ring_init(&worker->current_list); //current_list环初始化
image_cache_init(&worker->image_cache); //图像缓存初始化
image_surface_init(worker); //图像表面初始化
drawables_init(worker); //drawables初始化 主要是把drawables放到free_drawables链表中
cursor_items_init(worker);//cursor_item_init初始化 主要是把cursor的item放到free_cursor_item链表中
red_init_streams(worker); //stream流初始化 其中的成员streames 环初始化(两个向后指针都指向自己),free_streams=NULL,streams_buf[i]中的stream全部放到worker的free_streams中
stat_init(&worker->add_stat, add_stat_name); //把add_stat_name赋给add_stat
stat_init(&worker->exclude_stat, exclude_stat_name);//把exclude_stat_name赋给exclude_stat
stat_init(&worker->__exclude_stat, __exclude_stat_name);
#ifdef RED_STATISTICS //下面都是用于做统计的
char worker_str[20];
sprintf(worker_str, "display[%d]", worker->id);
worker->stat = stat_add_node(INVALID_STAT_REF, worker_str, TRUE);//状态检测??
worker->wakeup_counter = stat_add_counter(worker->stat, "wakeups", TRUE); //wakeup计数器
worker->command_counter = stat_add_counter(worker->stat, "commands", TRUE);//command计数器
#endif //上面都是用于统计的
for (i = 0; i < MAX_EVENT_SOURCES; i++) {
worker->poll_fds[i].fd = -1;
} //对worker中的poll_fds数组进行初始化,即每个pollfd结构的fd描述符都赋值为-1
worker->poll_fds[0].fd = worker->channel; //添加一个事件套接字描述符
worker->poll_fds[0].events = POLLIN; //事件类型为输入
worker->watches[0].worker = worker; //worker
worker->watches[0].watch_func = handle_dev_input;//处理输入的函数handle_dev_input
worker->watches[0].watch_func_opaque = worker; //函数handle_dev_input的参数为worker
red_memslot_info_init(&worker->mem_slots,
init_data->num_memslots_groups,
init_data->num_memslots,
init_data->memslot_gen_bits,
init_data->memslot_id_bits,
init_data->internal_groupslot_id);//初始化worker中的memslots结构
spice_warn_if(init_data->n_surfaces > NUM_SURFACES);
worker->n_surfaces = init_data->n_surfaces; //表面数的赋值
if (!spice_timer_queue_create()) { //创建定时器队列,并进行判断
spice_error("failed to create timer queue");
}
srand(time(NULL)); //随机数的初始化
message = RED_WORKER_MESSAGE_READY; //为mesage赋值为ready
write_message(worker->channel, &message); //向主线程中写入ready信息,告诉主线程 初始化完毕,请指示下一步工作
}