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