⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄

📁 兼容内核漫谈 适合想将Windows上的程序移植到其它平台上的朋友研究查看
💻
📖 第 1 页 / 共 3 页
字号:
    int err;

    *hObject = NULL;

    /* retrieve the name */
    err = fetch_oname(&oname,name);
    if (err<0)
        return ERR_PTR(err);

    /* allocate an object */
    obj = _AllocObject(clss,&oname,data);
    if (oname.name) putname(oname.name);
    if (IS_ERR(obj))
        return obj;

    /* find a handle slot */
    process = GetWineProcess(thread);
    epobj = &process->wp_handles[MAXHANDLES];
    write_lock(&process->wp_lock);
    for (ppobj=process->wp_handles; ppobj<epobj; ppobj++)
        if (!*ppobj)  goto found_handle;

    write_unlock(&process->wp_lock);
    objput(obj);
    return ERR_PTR(-EMFILE);

    found_handle:
    /* make link to object */
    objget(obj);
    *ppobj = obj;
    write_unlock(&process->wp_lock);
    ppobj++; /* don't use the NULL handle */
    *hObject = (HANDLE) ((char*)ppobj - (char*)process->wp_handles);
    return obj;
} /* end CreateObject() */[/code]

    这个函数的操作可以分成两大部分。第一部分是对_AllocObject()的调用,旨在创建具体的对象。第二部分是将指向所创建对象的指针“安装”在当前进程的“打开对象表”中,并将相应的下标转换成Handle。为便于阅读讨论,我们先假定第一部分的操作业已完成,_AllocObject()已经返回所创建的Object结构的指针,先看看对于“打开对象表”的操作,这是从注释行“/* find a handle slot */”开始的。至于putname()、objget ()、objput()一类的函数,那只是递增或递减数据结构中的引用计数(减到0就要释放其占用的存储空间),并不影响对于实质性操作的讨论。
    “打开对象表”在WineProcess数据结构中,而从上面传下来的只是个WineThread指针。所以这里要通过GetWineProcess()找到当前线程所属的Wine进程,这其实只是从WineThread数据结构中获取其wt_process指针而已。
    找到了所属进程的WineProcess数据结构以后,就通过一个for循环扫描其“打开对象表”,旨在找到一个空闲的位置,指针为0就表示空闲。这也说明了为什么0不能被用作handle的值。找到以后,就把新创建对象的obj指针填写到这个位置上。而handle数值的计算,则可以看出基本上是该指针在数组中的(字节)位移量加4,实际上就是下标加1后再乘4。注意handle的值是通过调用参数hObject返回的。
    再回到第一部分,即对象的创建,这是由_AllocObject()完成的。

[code][CreateSemaphoreA() > CreateObject() > _AllocObject()]

static Object *_AllocObject(struct ObjectClass *clss, struct oname *name, void *data)
{
    Object *obj;

    . . . . . .
    /* create and initialise an object */
    obj = (Object *) kmalloc(sizeof(Object),GFP_KERNEL);
    . . . . . .
    atomic_set(&obj->o_count,1);
    init_waitqueue_head(&obj->o_wait);
    . . . . . .
    /* name anonymous objects as "class:objaddr" if so requested */
    if (!name->name && ~clss->oc_flags&OCF_DONT_NAME_ANON) {
     . . . . . .
    }
    /* cut'n'paste the name from the caller's name buffer */
    else {
        obj->o_name.name = name->name;
        obj->o_name.nhash = name->nhash;
     name->name = NULL;
    }   

    /* attach to appropriate object class list */
    obj->o_class = clss;
    if (obj->o_name.name)
     list_add(&obj->o_objlist,
    &clss->oc_nobjs[obj->o_name.nhash&OBJCLASSNOBJSMASK]);
    else
        list_add(&obj->o_objlist,&clss->oc_aobjs);
    . . . . . .
    err = clss->constructor(obj,data); /* call the object constructor */
    if (err==0)  goto cleanup_1;

    . . . . . .
    cleanup_1:
    write_unlock(&clss->oc_lock);
    cleanup_0:
    return obj;
   } /* end _AllocObject() */[/code]

    首先是由kmalloc()为所创建的对象分配存储空间。然后是Object结构的初始化,包括把对象名(及其hash值)拷贝到Object结构中的o_name里面。
    接着,如果有对象名,就根据其hash值把所创建的Object结构挂入所属对象类别的相应hash队列中,否则就挂入该类别的无名对象队列中。
    下面就是实质性的操作了,这是通过所属类别提供的constructor函数完成的。对于“信号量”而言,该类对象的类型数据结构是semaphore_objclass。

[code]struct ObjectClass semaphore_objclass = {
    oc_type: "SEMA ",
    constructor: SemaphoreConstructor,
    reconstructor: SemaphoreReconstructor,
    destructor: SemaphoreDestructor,
    poll:  SemaphorePoll,
    describe: SemaphoreDescribe
};[/code]

   显然,其constructor函数是SemaphoreConstructor(),所以实际调用的就是这个函数。

[code][CreateSemaphoreA() > CreateObject() > _AllocObject() > SemaphoreConstructor()]

static int SemaphoreConstructor(Object *obj, void *data)
{
    struct WiocCreateSemaphoreA *args = data;
    struct WineSemaphore *semaphore;

    . . . . . .
    semaphore =
   (struct WineSemaphore *) kmalloc(sizeof(struct WineSemaphore), GFP_KERNEL);
    . . . . . .
    obj->o_private = semaphore;
    semaphore->ws_count = args->lInitialCount;
    semaphore->ws_max   = args->lMaximumCount;
    return 0;
} /* end SemaphoreConstructor() */[/code]

    程序很简单,先分配一个WineSemaphore数据结构所需的空间,这个数据结构才是真正意义上的具体的“对象”、一个信号量。当然,还要使Object结构中的指针o_private指向这个WineSemaphore数据结构。而对于这个信号量的初始化,则只不过是把作为参数传下来的lInitialCount和lMaximumCount填写进去。
    显然,kernel-win32另行实现了一个信号量机制,而不是把Windows应用程序的信号量操作“嫁接”到Linux已有的信号量机制上。对于相对而言比较简单的信号量机制,这样当然也是可以的(也还值得推敲)。而对于比较复杂的机制、特别是文件操作,那就只能走嫁接这“华山一条路”了,以后我们还要通过文件操作看kernel-win32是如何实现这种嫁接的。

    此外,前面曾经提到,task_ornament数据结构中有个指针to_ops,指向某个task_ornament_operations数据结构。这个数据结构的主体是一组函数指针,说明内核在close、exit、signal、execve、fork等操作时应该对上述种种附加的数据结构和对象做些什么。目前kernel-win32只定义了一种task_ornament_operations数据结构:

[code]static const struct task_ornament_operations wineserver_ornament_ops = {
    name:  "wineserver",
    owner:  THIS_MODULE,
    close:  ThreadOrnamentClose,
    exit:   ThreadOrnamentExit,
    signal:  ThreadOrnamentSignal,
    execve:  ThreadOrnamentExecve,
    fork:   ThreadOrnamentFork
};[/code]
   那么怎样使用这个数据结构呢?与这些函数指针基本对应,kernel-win32的代码中还有下列几个函数:
[code]   task_ornament_notify_exit()、
   task_ornament_notify_signal()、
   task_ornament_notify_execve()、
   task_ornament_notify_fork()、[/code]
   这些函数会根据相应的函数指针调用有关的程序。对这几个函数的调用则出现在kernel-win32对Linux内核所打的补丁中。以对于fork.c所打的补丁为例:

[code]do_fork(. . . . . .)
{
     . . . . . .
     p->p_cptr = NULL;
     init_waitqueue_head(&p->wait_chldexit);
     p->vfork_sem = NULL;
   - spin_lock_init(&p->alloc_lock);
   + rwlock_init(&p->alloc_lock);
     . . . . . .
     current->counter >>= 1;
     if (!current->counter)
         current->need_resched = 1;
   + /*
   +  * tell any ornaments to duplicate themselves
   +  */
   + INIT_LIST_HEAD(&p->ornaments);
   + task_ornament_notify_fork(current,p,clone_flags);
      . . . . . .
}[/code]
这里作的第一个修改是把spin_lock_init()换成rwlock_init()。下面实质性的修改则是将子进程(线程)的ornaments队列头加以初始化,然后调用task_ornament_notify_fork()。调用的目的,按注释所述,是复制当前进程(线程)的ornaments队列中的各个附件。

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -