wineserver的创建到读取请求

wineserver踊跃管理client的文件描述符之类,因为windows下的文件句柄和linux下的文件描述符有区别
clien发送请求给wineserver,wineserver相应client的请求。

首先进入main函数,在main函数里调用open_master_socket来创建一个套接字,该套接字用于监听client的连接。
在open_master_socket里的foreground决定了wineserver是在前台运行还是在后台运行。如是在后台运行,还使用了一对管道来同步创建过程的小技巧。
在里open_master_socket,套接字创建是在acquire_lock里完成的,acquire_lock,顾名思义,就是去获取一把锁,目的是避免在一个系统里出现多个wineserver实例。这里利用的是linux的

文件锁。

由acquire_lock里的socket( AF_UNIX, SOCK_STREAM, 0 )知创建的是一个unix域套接字。
其中有意思的两句是
atexit( socket_cleanup );
chmod( server_socket_name, 0600 );  /* make sure no other user can connect */
因为是unix域套接字,会创建出一个名为server_socket_name的文件,在wineserver结束后该文件依然存在。atexit的作用是注册终止函数(即main执行结束后调用的函数),使用atexit后,

不管wineserver是否是正常或异常退出,都会去调用socket_cleanup函数,在该函数里执行删除server_socket_name的操作。
chmod( server_socket_name, 0600 )的目的是通过更改文件属性来保证没有其他的程序能讲server_socket_name再当做unix域套接字名字使用了。

分配出来的fd放到master_socket结构体里的。
struct master_socket
{
    struct object        obj;        /* object header */
    struct fd           *fd;         /* file descriptor of the master socket */
};
在wineserver里有个对象的概念,在wineserver下的实例几乎都带有struct object结构体,如同c++里的基类。refcount是引用计数,,管理该对象的生命周期,ops是该对象的可实施的操作

,不同的对象有不同的操作。如没有操作,对应的位置上是NULL。这里主要关注同master_socket->fd绑定的master_socket_fd_ops,他其实只有一个操作,就是有client连接时,在accept时

的一些操作。
struct object
{
    unsigned int              refcount;    /* reference count */
    const struct object_ops  *ops;
    struct list               wait_queue;
    struct object_name       *name;
    struct security_descriptor *sd;
#ifdef DEBUG_OBJECTS
    struct list               obj_list;
#endif
};

然后set_fd_events( master_socket->fd, POLLIN ),说明监听POLLIN事件,对于listen,就是等待client接入的事件了。
由此只是通过set_fd_events来设置希望fd检测的事件,设为-1是移除。

来了一个client连接,就会调master_socket_poll_event的master_socket_fd_ops操作,他accept了client,同时通过create_process创建一个对应的进程对象来映射一个windows程序。

在create_process里,通过process = alloc_object( &process_ops )创建了一个进程对象,
然后list_add_tail( &process_list, &process->entry );加入到一个全局的进程列表里。

然后将client的文件描述符同操作绑定在一起
process->msg_fd = create_anonymous_fd( &process_fd_ops, fd, &process->obj, 0 )
然后等待事件set_fd_events( process->msg_fd, POLLIN ); 

当client有请求到来会到process_fd_ops的process_poll_event,然后调用receive_fd处理函数

在create_process里,还会调用create_thread创建一个线程的对象,因为一个进程至少有一个线程。

这里要注意的是,该线程对象也能和client通信。他是怎么做到的呢,原来,他在server端创建了一个管道pipe(request_pipe),然后把一个管道描述符发送到client端去。如何传送文件描

述符在《高级unix环境编程》高级进程间通信一节有讲述。

在create_thread里,我们可以看到线程对象绑定的是thread_ops操作,线程描述符对象绑定的是thread_fd_ops操作。

还有要注意的是create_prthread返回的并不是一个process对象,而是创建出来的thread对象。

client端的请求request实际是发向线程的fd的,因此触发的是thread_fd_ops操作。thread_fd_ops操作的poll_event是thread_poll_event;

我们看看
static void thread_poll_event( struct fd *fd, int event )
{
    struct thread *thread = get_fd_user( fd );
    assert( thread->obj.ops == &thread_ops );

    grab_object( thread );
    if (event & (POLLERR | POLLHUP)) kill_thread( thread, 0 );
    else if (event & POLLIN) read_request( thread );
    else if (event & POLLOUT) write_reply( thread );
    release_object( thread );
}

POLLIN读取请求,POLLOUT回复请求。

这里提一下grab_object和release_object,用于管理对象,调一次grab_object,其应用计数就加一,release_object就减一,为0时删除。

先看看读取请求read_request,当读取到一包正确的请求后就调用call_req_handler函数。call_req_handler函数里会根据请求号通过req_handlers调用对应的处理函数。请求号在enum

request里。
处理完请求后调用send_reply( &reply );发送请求。
由里的
        if ((current->reply_towrite = current->reply_size - (ret - sizeof(*reply))))
        {
            /* couldn't write it all, wait for POLLOUT */
            set_fd_events( current->reply_fd, POLLOUT );
            set_fd_events( current->request_fd, 0 );
            return;
        }
知,在发送完一单回复前,是不会接受新请求的。

 

 

 

 

 

 

 

通过undef DEBUG_OBJECTS来提点速?
通过变128为256来提速?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值