Whamcloud - gitweb
b=16098
[fs/lustre-release.git] / libcfs / libcfs / winnt / winnt-prim.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 [sun.com URL with a
20  * copy of GPLv2].
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
37 #define DEBUG_SUBSYSTEM S_LNET
38
39 #include <libcfs/libcfs.h>
40
41
42 /*
43  *  Thread routines
44  */
45
46 /*
47  * cfs_thread_proc
48  *   Lustre thread procedure wrapper routine (It's an internal routine)
49  *
50  * Arguments:
51  *   context:  a structure of cfs_thread_context_t, containing
52  *             all the necessary parameters
53  *
54  * Return Value:
55  *   void: N/A
56  *
57  * Notes: 
58  *   N/A
59  */
60
61 void
62 cfs_thread_proc(
63     void * context
64     )
65 {
66     cfs_thread_context_t * thread_context = 
67         (cfs_thread_context_t *) context;
68
69     /* Execute the specified function ... */
70
71     if (thread_context->func) {
72         (thread_context->func)(thread_context->arg);
73     }
74
75     /* Free the context memory */
76    
77     cfs_free(context);
78
79     /* Terminate this system thread */
80
81     PsTerminateSystemThread(STATUS_SUCCESS);
82 }
83
84 /*
85  * cfs_kernel_thread
86  *   Create a system thread to execute the routine specified
87  *
88  * Arguments:
89  *   func:  function to be executed in the thread
90  *   arg:   argument transferred to func function
91  *   flag:  thread creation flags.
92  *
93  * Return Value:
94  *   int:   0 on success or error codes
95  *
96  * Notes: 
97  *   N/A
98  */
99
100 int cfs_kernel_thread(int (*func)(void *), void *arg, int flag)
101 {
102     cfs_handle_t  thread = NULL;
103     NTSTATUS      status;
104     cfs_thread_context_t * context = NULL;
105
106     /* Allocate the context to be transferred to system thread */
107
108     context = cfs_alloc(sizeof(cfs_thread_context_t), CFS_ALLOC_ZERO);
109
110     if (!context) {
111         return -ENOMEM;
112     }
113
114     context->func  = func;
115     context->arg   = arg;
116
117     /* Create system thread with the cfs_thread_proc wrapper */
118
119     status = PsCreateSystemThread(
120                 &thread,
121                 (ACCESS_MASK)0L,
122                 0, 0, 0,
123                 cfs_thread_proc,
124                 context);
125
126     if (!NT_SUCCESS(status)) {
127
128
129         cfs_free(context);
130
131         /* We need translate the nt status to linux error code */
132
133         return cfs_error_code(status);
134     }
135
136     //
137     //  Query the thread id of the newly created thread
138     //
139
140     ZwClose(thread);
141
142     return 0;
143 }
144
145
146 /*
147  * Symbols routines
148  */
149
150
151 static CFS_DECL_RWSEM(cfs_symbol_lock);
152 CFS_LIST_HEAD(cfs_symbol_list);
153
154 int MPSystem = FALSE;
155
156 /*
157  * cfs_symbol_get
158  *   To query the specified symbol form the symbol table
159  *
160  * Arguments:
161  *   name:  the symbol name to be queried
162  *
163  * Return Value:
164  *   If the symbol is in the table, return the address of it.
165  *   If not, return NULL.
166  *
167  * Notes: 
168  *   N/A
169  */
170
171 void *
172 cfs_symbol_get(const char *name)
173 {
174     struct list_head    *walker;
175     struct cfs_symbol   *sym = NULL;
176
177     down_read(&cfs_symbol_lock);
178     list_for_each(walker, &cfs_symbol_list) {
179         sym = list_entry (walker, struct cfs_symbol, sym_list);
180         if (!strcmp(sym->name, name)) {
181             sym->ref ++;
182             break;
183         } 
184     } 
185     up_read(&cfs_symbol_lock);
186
187     if (sym != NULL) 
188         return sym->value;
189
190     return NULL;
191 }
192
193 /*
194  * cfs_symbol_put
195  *   To decrease the reference of  the specified symbol
196  *
197  * Arguments:
198  *   name:  the symbol name to be dereferred
199  *
200  * Return Value:
201  *   N/A
202  *
203  * Notes: 
204  *   N/A
205  */
206
207 void
208 cfs_symbol_put(const char *name)
209 {
210     struct list_head    *walker;
211     struct cfs_symbol   *sym = NULL;
212
213     down_read(&cfs_symbol_lock);
214     list_for_each(walker, &cfs_symbol_list) {
215         sym = list_entry (walker, struct cfs_symbol, sym_list);
216         if (!strcmp(sym->name, name)) {
217             LASSERT(sym->ref > 0);
218             sym->ref--;
219             break;
220         } 
221     } 
222     up_read(&cfs_symbol_lock);
223
224     LASSERT(sym != NULL);
225 }
226
227
228 /*
229  * cfs_symbol_register
230  *   To register the specified symbol infromation
231  *
232  * Arguments:
233  *   name:  the symbol name to be dereferred
234  *   value: the value that the symbol stands for
235  *
236  * Return Value:
237  *   N/A
238  *
239  * Notes: 
240  *   Zero: Succeed to register
241  *   Non-Zero: Fail to register the symbol
242  */
243
244 int
245 cfs_symbol_register(const char *name, const void *value)
246 {
247     struct list_head    *walker;
248     struct cfs_symbol   *sym = NULL;
249     struct cfs_symbol   *new = NULL;
250
251     new = cfs_alloc(sizeof(struct cfs_symbol), CFS_ALLOC_ZERO);
252     if (!new) {
253         return (-ENOMEM);
254     }
255     strncpy(new->name, name, CFS_SYMBOL_LEN);
256     new->value = (void *)value;
257     new->ref = 0;
258     CFS_INIT_LIST_HEAD(&new->sym_list);
259
260     down_write(&cfs_symbol_lock);
261     list_for_each(walker, &cfs_symbol_list) {
262         sym = list_entry (walker, struct cfs_symbol, sym_list);
263         if (!strcmp(sym->name, name)) {
264             up_write(&cfs_symbol_lock);
265             cfs_free(new);
266             return 0; // alreay registerred
267         }
268     }
269     list_add_tail(&new->sym_list, &cfs_symbol_list);
270     up_write(&cfs_symbol_lock);
271
272     return 0;
273 }
274
275 /*
276  * cfs_symbol_unregister
277  *   To unregister/remove the specified symbol
278  *
279  * Arguments:
280  *   name:  the symbol name to be dereferred
281  *
282  * Return Value:
283  *   N/A
284  *
285  * Notes: 
286  *   N/A
287  */
288
289 void
290 cfs_symbol_unregister(const char *name)
291 {
292     struct list_head    *walker;
293     struct list_head    *nxt;
294     struct cfs_symbol   *sym = NULL;
295
296     down_write(&cfs_symbol_lock);
297     list_for_each_safe(walker, nxt, &cfs_symbol_list) {
298         sym = list_entry (walker, struct cfs_symbol, sym_list);
299         if (!strcmp(sym->name, name)) {
300             LASSERT(sym->ref == 0);
301             list_del (&sym->sym_list);
302             cfs_free(sym);
303             break;
304         }
305     }
306     up_write(&cfs_symbol_lock);
307 }
308
309 /*
310  * cfs_symbol_clean
311  *   To clean all the symbols
312  *
313  * Arguments:
314  *   N/A
315  *
316  * Return Value:
317  *   N/A
318  *
319  * Notes: 
320  *   N/A
321  */
322
323 void
324 cfs_symbol_clean()
325 {
326     struct list_head    *walker;
327     struct cfs_symbol   *sym = NULL;
328
329     down_write(&cfs_symbol_lock);
330     list_for_each(walker, &cfs_symbol_list) {
331         sym = list_entry (walker, struct cfs_symbol, sym_list);
332         LASSERT(sym->ref == 0);
333         list_del (&sym->sym_list);
334         cfs_free(sym);
335     }
336     up_write(&cfs_symbol_lock);
337     return;
338 }
339
340
341
342 /*
343  * Timer routines
344  */
345
346
347 /* Timer dpc procedure */
348  
349 static void
350 cfs_timer_dpc_proc (
351     IN PKDPC Dpc,
352     IN PVOID DeferredContext,
353     IN PVOID SystemArgument1,
354     IN PVOID SystemArgument2)
355 {
356     cfs_timer_t *   timer;
357     KIRQL           Irql;
358
359     timer = (cfs_timer_t *) DeferredContext;
360
361     /* clear the flag */
362     KeAcquireSpinLock(&(timer->Lock), &Irql);
363     cfs_clear_flag(timer->Flags, CFS_TIMER_FLAG_TIMERED);
364     KeReleaseSpinLock(&(timer->Lock), Irql);
365
366     /* call the user specified timer procedure */
367     timer->proc((unsigned long)(timer->arg));
368 }
369
370 /*
371  * cfs_timer_init
372  *   To initialize the cfs_timer_t
373  *
374  * Arguments:
375  *   timer:  the cfs_timer to be initialized
376  *   func:   the timer callback procedure
377  *   arg:    argument for the callback proc
378  *
379  * Return Value:
380  *   N/A
381  *
382  * Notes: 
383  *   N/A
384  */
385
386 void cfs_timer_init(cfs_timer_t *timer, void (*func)(unsigned long), void *arg)
387 {
388     memset(timer, 0, sizeof(cfs_timer_t));
389
390     timer->proc = func;
391     timer->arg  = arg;
392
393     KeInitializeSpinLock(&(timer->Lock));
394     KeInitializeTimer(&timer->Timer);
395     KeInitializeDpc (&timer->Dpc, cfs_timer_dpc_proc, timer);
396
397     cfs_set_flag(timer->Flags, CFS_TIMER_FLAG_INITED);
398 }
399
400 /*
401  * cfs_timer_done
402  *   To finialize the cfs_timer_t (unused)
403  *
404  * Arguments:
405  *   timer:  the cfs_timer to be cleaned up
406  *
407  * Return Value:
408  *   N/A
409  *
410  * Notes: 
411  *   N/A
412  */
413
414 void cfs_timer_done(cfs_timer_t *timer)
415 {
416     return;
417 }
418
419 /*
420  * cfs_timer_arm
421  *   To schedule the timer while touching @deadline
422  *
423  * Arguments:
424  *   timer:  the cfs_timer to be freed
425  *   dealine: timeout value to wake up the timer
426  *
427  * Return Value:
428  *   N/A
429  *
430  * Notes: 
431  *   N/A
432  */
433
434 void cfs_timer_arm(cfs_timer_t *timer, cfs_time_t deadline)
435 {
436     LARGE_INTEGER   timeout;
437     KIRQL           Irql;
438
439     KeAcquireSpinLock(&(timer->Lock), &Irql);
440     if (!cfs_is_flag_set(timer->Flags, CFS_TIMER_FLAG_TIMERED)){
441
442         timeout.QuadPart = (LONGLONG)-1*1000*1000*10/HZ*deadline;
443
444         if (KeSetTimer(&timer->Timer, timeout, &timer->Dpc )) {
445             cfs_set_flag(timer->Flags, CFS_TIMER_FLAG_TIMERED);
446         }
447
448         timer->deadline = deadline;
449     }
450
451     KeReleaseSpinLock(&(timer->Lock), Irql);
452 }
453
454 /*
455  * cfs_timer_disarm
456  *   To discard the timer to be scheduled
457  *
458  * Arguments:
459  *   timer:  the cfs_timer to be discarded
460  *
461  * Return Value:
462  *   N/A
463  *
464  * Notes: 
465  *   N/A
466  */
467
468 void cfs_timer_disarm(cfs_timer_t *timer)
469 {
470     KIRQL   Irql;
471
472     KeAcquireSpinLock(&(timer->Lock), &Irql);
473     KeCancelTimer(&(timer->Timer));
474     cfs_clear_flag(timer->Flags, CFS_TIMER_FLAG_TIMERED);
475     KeReleaseSpinLock(&(timer->Lock), Irql);
476 }
477
478
479 /*
480  * cfs_timer_is_armed
481  *   To check the timer is scheduled or not
482  *
483  * Arguments:
484  *   timer:  the cfs_timer to be checked
485  *
486  * Return Value:
487  *   1:  if it's armed.
488  *   0:  if it's not.
489  *
490  * Notes: 
491  *   N/A
492  */
493
494 int cfs_timer_is_armed(cfs_timer_t *timer)
495 {
496     int     rc = 0;
497     KIRQL   Irql;
498
499     KeAcquireSpinLock(&(timer->Lock), &Irql);
500     if (cfs_is_flag_set(timer->Flags, CFS_TIMER_FLAG_TIMERED)) {
501         rc = 1;
502     }
503     KeReleaseSpinLock(&(timer->Lock), Irql);
504
505     return rc;
506 }
507
508 /*
509  * cfs_timer_deadline
510  *   To query the deadline of the timer
511  *
512  * Arguments:
513  *   timer:  the cfs_timer to be queried
514  *
515  * Return Value:
516  *   the deadline value
517  *
518  * Notes: 
519  *   N/A
520  */
521
522 cfs_time_t cfs_timer_deadline(cfs_timer_t * timer)
523 {
524     return timer->deadline;
525 }
526
527 /*
528  * daemonize routine stub
529  */
530
531 void cfs_daemonize(char *str)
532 {
533     return;
534 }
535
536 /*
537  *  routine related with sigals
538  */
539
540 cfs_sigset_t cfs_get_blockedsigs()
541 {
542         return 0;
543 }
544
545 cfs_sigset_t cfs_block_allsigs()
546 {
547         return 0;
548 }
549
550 cfs_sigset_t cfs_block_sigs(sigset_t bit)
551 {
552         return 0;
553 }
554
555 void cfs_restore_sigs(cfs_sigset_t old)
556 {
557 }
558
559 int cfs_signal_pending(void)
560 {
561     return 0;
562 }
563
564 void cfs_clear_sigpending(void)
565 {
566     return;
567 }
568
569 /**
570  **  Initialize routines 
571  **/
572
573 int
574 libcfs_arch_init(void)
575
576     int         rc;
577
578     spinlock_t  lock;
579     /* Workground to check the system is MP build or UP build */
580     spin_lock_init(&lock);
581     spin_lock(&lock);
582     MPSystem = (int)lock.lock;
583     /* MP build system: it's a real spin, for UP build system, it
584        only raises the IRQL to DISPATCH_LEVEL */
585     spin_unlock(&lock);
586
587     /* create slab memory caches for page alloctors */
588     cfs_page_t_slab = cfs_mem_cache_create(
589         "CPGT", sizeof(cfs_page_t), 0, 0 );
590
591     cfs_page_p_slab = cfs_mem_cache_create(
592         "CPGP", CFS_PAGE_SIZE, 0, 0 );
593
594     if ( cfs_page_t_slab == NULL ||
595          cfs_page_p_slab == NULL ){
596         rc = -ENOMEM;
597         goto errorout;
598     }    
599
600     rc = init_task_manager();
601
602     if (rc != 0) {
603         cfs_enter_debugger();
604         KdPrint(("winnt-prim.c:libcfs_arch_init: error initializing task manager ...\n"));
605         goto errorout;
606     }
607
608     /* initialize the proc file system */
609     rc = proc_init_fs();
610
611     if (rc != 0) {
612         cfs_enter_debugger();
613         KdPrint(("winnt-prim.c:libcfs_arch_init: error initializing proc fs ...\n"));
614         cleanup_task_manager();
615         goto errorout;
616     }
617
618     /* initialize the tdi data */
619     rc = ks_init_tdi_data();
620
621     if (rc != 0) {
622         cfs_enter_debugger();
623         KdPrint(("winnt-prim.c:libcfs_arch_init: error initializing tdi ...\n"));
624         proc_destroy_fs();
625         cleanup_task_manager();
626         goto errorout;
627     }
628
629 errorout:
630
631     if (rc != 0) {
632         /* destroy the taskslot cache slab */
633         if (cfs_page_t_slab) {
634             cfs_mem_cache_destroy(cfs_page_t_slab);
635         }
636         if (cfs_page_p_slab) {
637             cfs_mem_cache_destroy(cfs_page_p_slab);
638         }
639     }
640
641     return rc;
642 }
643
644 void
645 libcfs_arch_cleanup(void)
646 {
647     /* finialize the tdi data */
648     ks_fini_tdi_data();
649
650     /* detroy the whole proc fs tree and nodes */
651     proc_destroy_fs();
652
653     /* destroy the taskslot cache slab */
654     if (cfs_page_t_slab) {
655         cfs_mem_cache_destroy(cfs_page_t_slab);
656     }
657
658     if (cfs_page_p_slab) {
659         cfs_mem_cache_destroy(cfs_page_p_slab);
660     }
661
662         return; 
663 }
664
665 EXPORT_SYMBOL(libcfs_arch_init);
666 EXPORT_SYMBOL(libcfs_arch_cleanup);