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