Whamcloud - gitweb
b=16098
[fs/lustre-release.git] / libcfs / libcfs / winnt / winnt-curproc.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * libcfs/libcfs/winnt/winnt-curproc.c
37  *
38  * Impletion of winnt curproc routines.
39  */
40
41 #define DEBUG_SUBSYSTEM S_LNET
42
43 #include <libcfs/libcfs.h>
44
45
46 /*
47  * Implementation of cfs_curproc API (see portals/include/libcfs/curproc.h)
48  * for Linux kernel.
49  */
50
51 cfs_task_t this_task = 
52     { 0, 0, 0, 0, 0, 0, 0, 
53       0, 0, 0, 0,  1, 0,  0, 0, 0,
54       "sysetm\0" };
55
56
57 uid_t  cfs_curproc_uid(void)
58 {
59     return this_task.uid;
60 }
61
62 gid_t  cfs_curproc_gid(void)
63 {
64     return this_task.gid;
65 }
66
67 uid_t  cfs_curproc_fsuid(void)
68 {
69     return this_task.fsuid;
70 }
71
72 gid_t cfs_curproc_fsgid(void)
73 {
74     return this_task.fsgid;
75 }
76
77 pid_t cfs_curproc_pid(void)
78 {
79     return cfs_current()->pid;
80 }
81
82 int cfs_curproc_groups_nr(void)
83 {
84     return this_task.ngroups;
85 }
86
87 void cfs_curproc_groups_dump(gid_t *array, int size)
88 {
89     LASSERT(size <= NGROUPS);
90     size = min_t(int, size, this_task.ngroups);
91     memcpy(array, this_task.groups, size * sizeof(__u32));
92 }
93
94 int cfs_curproc_is_in_groups(gid_t gid)
95 {
96     return in_group_p(gid);
97 }
98
99 mode_t cfs_curproc_umask(void)
100 {
101     return this_task.umask;
102 }
103
104 char  *cfs_curproc_comm(void)
105 {
106     return this_task.comm;
107 }
108
109 cfs_kernel_cap_t cfs_curproc_cap_get(void)
110 {
111     return this_task.cap_effective;
112 }
113
114 void cfs_curproc_cap_set(cfs_kernel_cap_t cap)
115 {
116     this_task.cap_effective = cap;
117 }
118
119
120 /*
121  * Implementation of linux task management routines
122  */
123
124
125 /* global of the task manager structure */
126
127 TASK_MAN TaskMan;
128
129
130 /*
131  *  task slot routiens
132  */
133
134 PTASK_SLOT
135 alloc_task_slot()
136 {
137     PTASK_SLOT task = NULL;
138
139     if (TaskMan.slab) {
140         task = cfs_mem_cache_alloc(TaskMan.slab, 0);
141     } else {
142         task = cfs_alloc(sizeof(TASK_SLOT), 0);
143     }
144
145     return task;
146 }
147
148 void
149 init_task_slot(PTASK_SLOT task)
150 {
151     memset(task, 0, sizeof(TASK_SLOT));
152     task->Magic = TASKSLT_MAGIC;
153     task->task  = this_task;
154     task->task.pid = (pid_t)PsGetCurrentThreadId();
155     cfs_init_event(&task->Event, TRUE, FALSE);
156 }
157
158
159 void
160 cleanup_task_slot(PTASK_SLOT task)
161 {
162     if (TaskMan.slab) {
163         cfs_mem_cache_free(TaskMan.slab, task);
164     } else {
165         cfs_free(task);
166     }
167 }
168
169 /*
170  *  task manager related routines
171  */
172
173 VOID
174 task_manager_notify(
175     IN HANDLE   ProcessId,
176     IN HANDLE   ThreadId,
177     IN BOOLEAN  Create
178     )
179 {
180     PLIST_ENTRY ListEntry = NULL; 
181     PTASK_SLOT  TaskSlot  = NULL;
182
183     spin_lock(&(TaskMan.Lock));
184
185     ListEntry = TaskMan.TaskList.Flink;
186
187     while (ListEntry != (&(TaskMan.TaskList))) {
188
189         TaskSlot = CONTAINING_RECORD(ListEntry, TASK_SLOT, Link);
190
191         if (TaskSlot->Pid == ProcessId && TaskSlot->Tid == ThreadId) {
192
193             if (Create) {
194 /*
195                 DbgPrint("task_manager_notify: Pid=%xh Tid %xh resued (TaskSlot->Tet = %xh)...\n",
196                          ProcessId, ThreadId, TaskSlot->Tet);
197 */
198             } else {
199                 /* remove the taskslot */
200                 RemoveEntryList(&(TaskSlot->Link));
201                 TaskMan.NumOfTasks--;
202
203                 /* now free the task slot */
204                 cleanup_task_slot(TaskSlot);
205             }
206         }
207
208         ListEntry = ListEntry->Flink;
209     }
210
211     spin_unlock(&(TaskMan.Lock));
212 }
213
214 int
215 init_task_manager()
216 {
217     NTSTATUS    status;
218
219     /* initialize the content and magic */
220     memset(&TaskMan, 0, sizeof(TASK_MAN));
221     TaskMan.Magic = TASKMAN_MAGIC;
222
223     /* initialize the spinlock protection */
224     spin_lock_init(&TaskMan.Lock);
225
226     /* create slab memory cache */
227     TaskMan.slab = cfs_mem_cache_create(
228         "TSLT", sizeof(TASK_SLOT), 0, 0);
229
230     /* intialize the list header */
231     InitializeListHead(&(TaskMan.TaskList));
232
233     /* set the thread creation/destruction notify routine */
234     status = PsSetCreateThreadNotifyRoutine(task_manager_notify);
235
236     if (!NT_SUCCESS(status)) {
237         cfs_enter_debugger();
238     }
239
240     return 0;
241 }
242
243 void
244 cleanup_task_manager()
245 {
246     PLIST_ENTRY ListEntry = NULL; 
247     PTASK_SLOT  TaskSlot  = NULL;
248
249     /* we must stay in system since we succeed to register the
250        CreateThreadNotifyRoutine: task_manager_notify */
251     cfs_enter_debugger();
252
253
254     /* cleanup all the taskslots attached to the list */
255     spin_lock(&(TaskMan.Lock));
256
257     while (!IsListEmpty(&(TaskMan.TaskList))) {
258
259         ListEntry = TaskMan.TaskList.Flink;
260         TaskSlot = CONTAINING_RECORD(ListEntry, TASK_SLOT, Link);
261
262         RemoveEntryList(ListEntry);
263         cleanup_task_slot(TaskSlot);
264     }
265
266     spin_unlock(&TaskMan.Lock);
267
268     /* destroy the taskslot cache slab */
269     cfs_mem_cache_destroy(TaskMan.slab);
270     memset(&TaskMan, 0, sizeof(TASK_MAN));
271 }
272
273
274 /*
275  * schedule routines (task slot list)
276  */
277
278
279 cfs_task_t *
280 cfs_current()
281 {
282     HANDLE      Pid = PsGetCurrentProcessId();
283     HANDLE      Tid = PsGetCurrentThreadId();
284     PETHREAD    Tet = PsGetCurrentThread();
285
286     PLIST_ENTRY ListEntry = NULL; 
287     PTASK_SLOT  TaskSlot  = NULL;
288
289     spin_lock(&(TaskMan.Lock));
290
291     ListEntry = TaskMan.TaskList.Flink;
292
293     while (ListEntry != (&(TaskMan.TaskList))) {
294
295         TaskSlot = CONTAINING_RECORD(ListEntry, TASK_SLOT, Link);
296
297         if (TaskSlot->Pid == Pid && TaskSlot->Tid == Tid) {
298             if (TaskSlot->Tet != Tet) {
299
300 /*
301                 DbgPrint("cfs_current: Pid=%xh Tid %xh Tet = %xh resued (TaskSlot->Tet = %xh)...\n",
302                          Pid, Tid, Tet, TaskSlot->Tet);
303 */
304                 //
305                 // The old thread was already exit. This must be a
306                 // new thread which get the same Tid to the previous.
307                 //
308
309                 TaskSlot->Tet = Tet;
310             }
311             break;
312
313         } else {
314
315             if ((ULONG)TaskSlot->Pid > (ULONG)Pid) {
316                 TaskSlot = NULL;
317                 break;
318             } else if ((ULONG)TaskSlot->Pid == (ULONG)Pid) {
319                 if ((ULONG)TaskSlot->Tid > (ULONG)Tid) {
320                     TaskSlot = NULL;
321                     break;
322                 }
323             }
324
325             TaskSlot =  NULL;
326         }
327
328         ListEntry = ListEntry->Flink;
329     }
330
331     if (!TaskSlot) {
332
333         TaskSlot = alloc_task_slot();
334
335         if (!TaskSlot) {
336             cfs_enter_debugger();
337             goto errorout;
338         }
339
340         init_task_slot(TaskSlot);
341
342         TaskSlot->Pid = Pid;
343         TaskSlot->Tid = Tid;
344         TaskSlot->Tet = Tet;
345
346         if (ListEntry == (&(TaskMan.TaskList))) {
347             //
348             // Empty case or the biggest case, put it to the tail.
349             //
350             InsertTailList(&(TaskMan.TaskList), &(TaskSlot->Link));
351         } else {
352             //
353             // Get a slot and smaller than it's tid, put it just before.
354             //
355             InsertHeadList(ListEntry->Blink, &(TaskSlot->Link));
356         }
357
358         TaskMan.NumOfTasks++;
359     }
360
361     //
362     // To Check whether he task structures are arranged in the expected order ?
363     //
364
365     {
366         PTASK_SLOT  Prev = NULL, Curr = NULL;
367         
368         ListEntry = TaskMan.TaskList.Flink;
369
370         while (ListEntry != (&(TaskMan.TaskList))) {
371
372             Curr = CONTAINING_RECORD(ListEntry, TASK_SLOT, Link);
373             ListEntry = ListEntry->Flink;
374
375             if (Prev) {
376                 if ((ULONG)Prev->Pid > (ULONG)Curr->Pid) {
377                     cfs_enter_debugger();
378                 } else if ((ULONG)Prev->Pid == (ULONG)Curr->Pid) {
379                     if ((ULONG)Prev->Tid > (ULONG)Curr->Tid) {
380                         cfs_enter_debugger();
381                     }
382                 }
383             }
384
385             Prev = Curr;
386         }
387     }
388
389 errorout:
390
391     spin_unlock(&(TaskMan.Lock));
392
393     if (!TaskSlot) {
394         cfs_enter_debugger();
395         return NULL;
396     }
397
398     return (&(TaskSlot->task));
399 }
400
401 int
402 schedule_timeout(int64_t time)
403 {
404     cfs_task_t * task = cfs_current();
405     PTASK_SLOT   slot = NULL;
406
407     if (!task) {
408         cfs_enter_debugger();
409         return 0;
410     }
411
412     slot = CONTAINING_RECORD(task, TASK_SLOT, task);
413     cfs_assert(slot->Magic == TASKSLT_MAGIC);
414
415     if (time == MAX_SCHEDULE_TIMEOUT) {
416         time = 0;
417     }
418
419     return (cfs_wait_event(&(slot->Event), time) != 0);
420 }
421
422 int
423 schedule()
424 {
425     return schedule_timeout(0);
426 }
427
428 int
429 wake_up_process(
430     cfs_task_t * task
431     )
432 {
433     PTASK_SLOT   slot = NULL;
434
435     if (!task) {
436         cfs_enter_debugger();
437         return 0;
438     }
439
440     slot = CONTAINING_RECORD(task, TASK_SLOT, task);
441     cfs_assert(slot->Magic == TASKSLT_MAGIC);
442
443     cfs_wake_event(&(slot->Event));
444
445     return TRUE;
446 }
447
448 void
449 sleep_on(
450     cfs_waitq_t *waitq
451     )
452 {
453         cfs_waitlink_t link;
454         
455         cfs_waitlink_init(&link);
456         cfs_waitq_add(waitq, &link);
457         cfs_waitq_wait(&link, CFS_TASK_INTERRUPTIBLE);
458         cfs_waitq_del(waitq, &link);
459 }
460
461 EXPORT_SYMBOL(cfs_curproc_uid);
462 EXPORT_SYMBOL(cfs_curproc_pid);
463 EXPORT_SYMBOL(cfs_curproc_gid);
464 EXPORT_SYMBOL(cfs_curproc_fsuid);
465 EXPORT_SYMBOL(cfs_curproc_fsgid);
466 EXPORT_SYMBOL(cfs_curproc_umask);
467 EXPORT_SYMBOL(cfs_curproc_comm);
468 EXPORT_SYMBOL(cfs_curproc_groups_nr);
469 EXPORT_SYMBOL(cfs_curproc_groups_dump);
470 EXPORT_SYMBOL(cfs_curproc_is_in_groups);
471 EXPORT_SYMBOL(cfs_curproc_cap_get);
472 EXPORT_SYMBOL(cfs_curproc_cap_set);