wine的异步实现机制

对兼容内核项目具体开发、代码、实现方案的讨论

版主: 古月今人, welfear

wine的异步实现机制

帖子byebye 于 2010-07-30 17:47

以WSARecv为例,来说一下wine的异步机制,采用wine-1.2的代码。
WSARecv是socket编程中用到的异步接收数据的函数。
在接收之前程序会调用socket()来创建一个socket,在wine中这是WS_socket(),最终会进入wineserver的函数create_socket(),这里会调用sock_reselect(),将socket的fd号写入一个全局的pollfd数据结构中。
然后看WSARecv(),这个函数会执行一遍recv,如果这个时候还没有数据到来,则向wineserver申请执行register_async,并设置回调函数为WS2_async_recv。
代码: 全选
SERVER_START_REQ( register_async )
{
    req->type           = ASYNC_TYPE_READ;
    req->async.handle   = wine_server_obj_handle( wsa->hSocket );
    req->async.callback = wine_server_client_ptr( WS2_async_recv );
    req->async.iosb     = wine_server_client_ptr( iosb );
    req->async.arg      = wine_server_client_ptr( wsa );
    req->async.event    = wine_server_obj_handle( lpCompletionRoutine ? 0 : lpOverlapped->hEvent );
    req->async.cvalue   = cvalue;
    err = wine_server_call( req );
}
SERVER_END_REQ;

wineserver在执行register_async时,会通过fd_ops寻找每个对象自己的queue_async函数指针,这里对应socket的是sock_queue_async(),然后调用到create_async(),将一个设置好的async数据结构挂入queue队列。然后wineserver返回,WSARecv也因此返回应用程序。
代码: 全选
struct async *create_async( struct thread *thread, struct async_queue *queue, const async_data_t *data )
{
    ......
    list_add_tail( &queue->queue, &async->queue_entry );
    ......
}

然后看真正的接收数据工作在哪儿做。
看wineserver的main_loop函数:
代码: 全选
void main_loop(void)
{
    int i, ret, timeout;

    set_current_time();
    server_start_time = current_time;

    main_loop_epoll();
    /* fall through to normal poll loop */

    while (active_users)
    {
        timeout = get_next_timeout();

        if (!active_users) break;  /* last user removed by a timeout */

        ret = poll( pollfd, nb_users, timeout );
        set_current_time();

        if (ret > 0)
        {
            for (i = 0; i < nb_users; i++)
            {
                if (pollfd[i].revents)
                {
                    fd_poll_event( poll_users[i], pollfd[i].revents );
                    if (!--ret) break;
                }
            }
        }
    }
}

这是wineserver的主循环,只要有windows进程在运行,这个循环会一直轮询下去。在这个循环里会调用poll函数,参数就是创建socket是写入fd的全局pollfd结构,然后进入等待数据的到来。
当客户端程序调用send之类的函数时,poll会因为有I/O请求而返回,然后进入fd_poll_event函数,一直调用到async_wake_up(),然后会遍历刚刚提到的queue队列,找到对应的async数据结构,然后进入async_terminate(),在这里将刚刚设置的回调函数WS2_async_recv()加入apc队列,当wineserver返回时会进入这个apc函数WS2_async_recv()
代码: 全选
void async_terminate( struct async *async, unsigned int status )
{
    ......
    memset( &data, 0, sizeof(data) );
    data.type            = APC_ASYNC_IO;
    data.async_io.func   = async->data.callback;
    data.async_io.user   = async->data.arg;
    data.async_io.sb     = async->data.iosb;
    data.async_io.status = status;
    thread_queue_apc( async->thread, &async->obj, &data );
    ......
}

在WS2_async_recv()里才真正调用recv函数来接收数据。
代码: 全选
static NTSTATUS WS2_async_recv( void* user, IO_STATUS_BLOCK* iosb, NTSTATUS status, void **apc)
{
    ws2_async* wsa = user;
    int result = 0, fd;

    switch (status)
    {
    case STATUS_ALERTED:
        if ((status = wine_server_handle_to_fd( wsa->hSocket, FILE_READ_DATA, &fd, NULL ) ))
            break;

        result = WS2_recv( fd, wsa );
        ......
        break;
    }
    ....
    return status;
}

这样就实现了一个异步的过程。
头像
byebye
 
帖子: 504
注册: 2008-10-09 10:10

回到 兼容内核开发

在线用户

正在浏览此版面的用户:Google [Bot] 和 1 位游客