?? 漫談兼容內核之二:關于kernel-win32的對象管理.txt
字號:
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 + -