Whamcloud - gitweb
f96bdd211f811a4d49db4c173fd693d7452094bf
[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
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
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_DECLARE_RWSEM(cfs_symbol_lock);
152 CFS_LIST_HEAD(cfs_symbol_list);
153
154 int libcfs_is_mp_system = 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     cfs_list_t              *walker;
175     struct cfs_symbol       *sym = NULL;
176
177     cfs_down_read(&cfs_symbol_lock);
178     cfs_list_for_each(walker, &cfs_symbol_list) {
179         sym = cfs_list_entry (walker, struct cfs_symbol, sym_list);
180         if (!strcmp(sym->name, name)) {
181             sym->ref ++;
182             break;
183         }
184     }
185     cfs_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     cfs_list_t              *walker;
211     struct cfs_symbol       *sym = NULL;
212
213     cfs_down_read(&cfs_symbol_lock);
214     cfs_list_for_each(walker, &cfs_symbol_list) {
215         sym = cfs_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     cfs_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     cfs_list_t              *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     cfs_down_write(&cfs_symbol_lock);
261     cfs_list_for_each(walker, &cfs_symbol_list) {
262         sym = cfs_list_entry (walker, struct cfs_symbol, sym_list);
263         if (!strcmp(sym->name, name)) {
264             cfs_up_write(&cfs_symbol_lock);
265             cfs_free(new);
266             return 0; // alreay registerred
267         }
268     }
269     cfs_list_add_tail(&new->sym_list, &cfs_symbol_list);
270     cfs_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     cfs_list_t              *walker;
293     cfs_list_t              *nxt;
294     struct cfs_symbol       *sym = NULL;
295
296     cfs_down_write(&cfs_symbol_lock);
297     cfs_list_for_each_safe(walker, nxt, &cfs_symbol_list) {
298         sym = cfs_list_entry (walker, struct cfs_symbol, sym_list);
299         if (!strcmp(sym->name, name)) {
300             LASSERT(sym->ref == 0);
301             cfs_list_del (&sym->sym_list);
302             cfs_free(sym);
303             break;
304         }
305     }
306     cfs_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     cfs_list_t          *walker;
327     struct cfs_symbol   *sym = NULL;
328
329     cfs_down_write(&cfs_symbol_lock);
330     cfs_list_for_each(walker, &cfs_symbol_list) {
331         sym = cfs_list_entry (walker, struct cfs_symbol, sym_list);
332         LASSERT(sym->ref == 0);
333         cfs_list_del (&sym->sym_list);
334         cfs_free(sym);
335     }
336     cfs_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((long_ptr_t)timer->arg);
368 }
369
370 void cfs_init_timer(cfs_timer_t *timer)
371 {
372     memset(timer, 0, sizeof(cfs_timer_t));
373 }
374
375 /*
376  * cfs_timer_init
377  *   To initialize the cfs_timer_t
378  *
379  * Arguments:
380  *   timer:  the cfs_timer to be initialized
381  *   func:   the timer callback procedure
382  *   arg:    argument for the callback proc
383  *
384  * Return Value:
385  *   N/A
386  *
387  * Notes:
388  *   N/A
389  */
390
391 void cfs_timer_init(cfs_timer_t *timer, void (*func)(ulong_ptr_t), void *arg)
392 {
393     memset(timer, 0, sizeof(cfs_timer_t));
394
395     timer->proc = func;
396     timer->arg  = arg;
397
398     KeInitializeSpinLock(&(timer->Lock));
399     KeInitializeTimer(&timer->Timer);
400     KeInitializeDpc (&timer->Dpc, cfs_timer_dpc_proc, timer);
401
402     cfs_set_flag(timer->Flags, CFS_TIMER_FLAG_INITED);
403 }
404
405 /*
406  * cfs_timer_done
407  *   To finialize the cfs_timer_t (unused)
408  *
409  * Arguments:
410  *   timer:  the cfs_timer to be cleaned up
411  *
412  * Return Value:
413  *   N/A
414  *
415  * Notes:
416  *   N/A
417  */
418
419 void cfs_timer_done(cfs_timer_t *timer)
420 {
421     return;
422 }
423
424 /*
425  * cfs_timer_arm
426  *   To schedule the timer while touching @deadline
427  *
428  * Arguments:
429  *   timer:  the cfs_timer to be freed
430  *   dealine: timeout value to wake up the timer
431  *
432  * Return Value:
433  *   N/A
434  *
435  * Notes:
436  *   N/A
437  */
438
439 void cfs_timer_arm(cfs_timer_t *timer, cfs_time_t deadline)
440 {
441     LARGE_INTEGER   timeout;
442     KIRQL           Irql;
443
444     KeAcquireSpinLock(&(timer->Lock), &Irql);
445     if (!cfs_is_flag_set(timer->Flags, CFS_TIMER_FLAG_TIMERED)){
446
447         timeout.QuadPart = (LONGLONG)-1*1000*1000*10/CFS_HZ*deadline;
448
449         if (KeSetTimer(&timer->Timer, timeout, &timer->Dpc)) {
450             cfs_set_flag(timer->Flags, CFS_TIMER_FLAG_TIMERED);
451         }
452
453         timer->deadline = deadline;
454     }
455
456     KeReleaseSpinLock(&(timer->Lock), Irql);
457 }
458
459 /*
460  * cfs_timer_disarm
461  *   To discard the timer to be scheduled
462  *
463  * Arguments:
464  *   timer:  the cfs_timer to be discarded
465  *
466  * Return Value:
467  *   N/A
468  *
469  * Notes:
470  *   N/A
471  */
472
473 void cfs_timer_disarm(cfs_timer_t *timer)
474 {
475     KIRQL   Irql;
476
477     KeAcquireSpinLock(&(timer->Lock), &Irql);
478     KeCancelTimer(&(timer->Timer));
479     cfs_clear_flag(timer->Flags, CFS_TIMER_FLAG_TIMERED);
480     KeReleaseSpinLock(&(timer->Lock), Irql);
481 }
482
483
484 /*
485  * cfs_timer_is_armed
486  *   To check the timer is scheduled or not
487  *
488  * Arguments:
489  *   timer:  the cfs_timer to be checked
490  *
491  * Return Value:
492  *   1:  if it's armed.
493  *   0:  if it's not.
494  *
495  * Notes:
496  *   N/A
497  */
498
499 int cfs_timer_is_armed(cfs_timer_t *timer)
500 {
501     int     rc = 0;
502     KIRQL   Irql;
503
504     KeAcquireSpinLock(&(timer->Lock), &Irql);
505     if (cfs_is_flag_set(timer->Flags, CFS_TIMER_FLAG_TIMERED)) {
506         rc = 1;
507     }
508     KeReleaseSpinLock(&(timer->Lock), Irql);
509
510     return rc;
511 }
512
513 /*
514  * cfs_timer_deadline
515  *   To query the deadline of the timer
516  *
517  * Arguments:
518  *   timer:  the cfs_timer to be queried
519  *
520  * Return Value:
521  *   the deadline value
522  *
523  * Notes:
524  *   N/A
525  */
526
527 cfs_time_t cfs_timer_deadline(cfs_timer_t * timer)
528 {
529     return timer->deadline;
530 }
531
532 /*
533  * daemonize routine stub
534  */
535
536 void cfs_daemonize(char *str)
537 {
538     return;
539 }
540
541 int cfs_daemonize_ctxt(char *str) {
542     cfs_daemonize(str);
543     return 0;
544 }
545
546 /*
547  *  routine related with sigals
548  */
549
550 cfs_sigset_t cfs_get_blockedsigs()
551 {
552         return 0;
553 }
554
555 cfs_sigset_t cfs_block_allsigs()
556 {
557         return 0;
558 }
559
560 cfs_sigset_t cfs_block_sigs(sigset_t bit)
561 {
562         return 0;
563 }
564
565 void cfs_restore_sigs(cfs_sigset_t old)
566 {
567 }
568
569 int cfs_signal_pending(void)
570 {
571     return 0;
572 }
573
574 void cfs_clear_sigpending(void)
575 {
576     return;
577 }
578
579 int cfs_need_resched(void)
580 {
581         return 0;
582 }
583
584 void cfs_cond_resched(void)
585 {
586 }
587
588 /*
589  *  thread cpu affinity routines
590  */
591
592 typedef struct _THREAD_BASIC_INFORMATION {
593     NTSTATUS ExitStatus;
594     PVOID TebBaseAddress;
595     CLIENT_ID ClientId;
596     ULONG_PTR AffinityMask;
597     KPRIORITY Priority;
598     LONG BasePriority;
599 } THREAD_BASIC_INFORMATION;
600
601 typedef THREAD_BASIC_INFORMATION *PTHREAD_BASIC_INFORMATION;
602
603 #define THREAD_QUERY_INFORMATION       (0x0040)
604
605 NTSYSAPI
606 NTSTATUS
607 NTAPI
608 ZwOpenThread (
609     __out PHANDLE ThreadHandle,
610     __in ACCESS_MASK DesiredAccess,
611     __in POBJECT_ATTRIBUTES ObjectAttributes,
612     __in_opt PCLIENT_ID ClientId
613     );
614
615 NTSYSAPI
616 NTSTATUS
617 NTAPI
618 ZwQueryInformationThread (
619     __in HANDLE ThreadHandle,
620     __in THREADINFOCLASS ThreadInformationClass,
621     __out_bcount(ThreadInformationLength) PVOID ThreadInformation,
622     __in ULONG ThreadInformationLength,
623     __out_opt PULONG ReturnLength
624     );
625
626 NTSYSAPI
627 NTSTATUS
628 NTAPI
629 ZwSetInformationThread (
630     __in HANDLE ThreadHandle,
631     __in THREADINFOCLASS ThreadInformationClass,
632     __in_bcount(ThreadInformationLength) PVOID ThreadInformation,
633     __in ULONG ThreadInformationLength
634     );
635
636 HANDLE
637 cfs_open_current_thread()
638 {
639     NTSTATUS         status;
640     HANDLE           handle = NULL;
641     OBJECT_ATTRIBUTES oa;
642     CLIENT_ID        cid;
643
644     /* initialize object attributes */
645     InitializeObjectAttributes( &oa, NULL, OBJ_KERNEL_HANDLE |
646                                 OBJ_CASE_INSENSITIVE, NULL, NULL);
647
648     /* initialize client id */
649     cid.UniqueProcess = PsGetCurrentProcessId();
650     cid.UniqueThread  = PsGetCurrentThreadId();
651
652     /* get thread handle */
653     status = ZwOpenThread( &handle, THREAD_QUERY_INFORMATION |
654                            THREAD_SET_INFORMATION, &oa, &cid);
655     if (!NT_SUCCESS(status)) {
656         handle = NULL;
657     }
658
659     return handle;
660 }
661
662 void
663 cfs_close_thread_handle(HANDLE handle)
664 {
665     if (handle)
666         ZwClose(handle);
667 }
668
669 KAFFINITY
670 cfs_query_thread_affinity()
671 {
672     NTSTATUS         status;
673     HANDLE           handle = NULL;
674     DWORD            size;
675     THREAD_BASIC_INFORMATION TBI = {0};
676
677     /* open current thread */
678     handle = cfs_open_current_thread();
679     if (!handle) {
680         goto errorout;
681     }
682
683     /* query thread cpu affinity */
684     status = ZwQueryInformationThread(handle, ThreadBasicInformation,
685                        &TBI, sizeof(THREAD_BASIC_INFORMATION), &size);
686     if (!NT_SUCCESS(status)) {
687         goto errorout;
688     }
689
690 errorout:
691
692     cfs_close_thread_handle(handle);
693     return TBI.AffinityMask;
694 }
695
696 int
697 cfs_set_thread_affinity(KAFFINITY affinity)
698 {
699     NTSTATUS         status;
700     HANDLE           handle = NULL;
701
702     /* open current thread */
703     handle = cfs_open_current_thread();
704     if (!handle) {
705         goto errorout;
706     }
707
708     /* set thread cpu affinity */
709     status = ZwSetInformationThread(handle, ThreadAffinityMask,
710                                     &affinity, sizeof(KAFFINITY));
711     if (!NT_SUCCESS(status)) {
712         goto errorout;
713     }
714
715 errorout:
716
717     cfs_close_thread_handle(handle);
718     return NT_SUCCESS(status);
719 }
720
721 int
722 cfs_tie_thread_to_cpu(int cpu)
723 {
724     return cfs_set_thread_affinity((KAFFINITY) (1 << cpu));
725 }
726
727 int
728 cfs_set_thread_priority(KPRIORITY priority)
729 {
730     NTSTATUS         status;
731     HANDLE           handle = NULL;
732
733     /* open current thread */
734     handle = cfs_open_current_thread();
735     if (!handle) {
736         goto errorout;
737     }
738
739     /* set thread cpu affinity */
740     status = ZwSetInformationThread(handle, ThreadPriority,
741                                     &priority, sizeof(KPRIORITY));
742     if (!NT_SUCCESS(status)) {
743         KdPrint(("set_thread_priority failed: %xh\n", status));
744         goto errorout;
745     }
746
747 errorout:
748
749     cfs_close_thread_handle(handle);
750     return NT_SUCCESS(status);
751 }
752
753 int cfs_need_resched(void)
754 {
755         return 0;
756 }
757
758 void cfs_cond_resched(void)
759 {
760 }
761
762 /**
763  **  Initialize routines
764  **/
765
766 void cfs_libc_init();
767
768 int
769 libcfs_arch_init(void)
770 {
771     int         rc;
772
773     cfs_spinlock_t  lock;
774     /* Workground to check the system is MP build or UP build */
775     cfs_spin_lock_init(&lock);
776     cfs_spin_lock(&lock);
777     libcfs_is_mp_system = (int)lock.lock;
778     /* MP build system: it's a real spin, for UP build system, it
779        only raises the IRQL to DISPATCH_LEVEL */
780     cfs_spin_unlock(&lock);
781
782     /* initialize libc routines (confliction between libcnptr.lib
783        and kernel ntoskrnl.lib) */
784     cfs_libc_init();
785
786     /* create slab memory caches for page alloctors */
787     cfs_page_t_slab = cfs_mem_cache_create(
788         "CPGT", sizeof(cfs_page_t), 0, 0 );
789
790     cfs_page_p_slab = cfs_mem_cache_create(
791         "CPGP", CFS_PAGE_SIZE, 0, 0 );
792
793     if ( cfs_page_t_slab == NULL ||
794          cfs_page_p_slab == NULL ){
795         rc = -ENOMEM;
796         goto errorout;
797     }
798
799     rc = init_task_manager();
800     if (rc != 0) {
801         cfs_enter_debugger();
802         KdPrint(("winnt-prim.c:libcfs_arch_init: error initializing task manager ...\n"));
803         goto errorout;
804     }
805
806     /* initialize the proc file system */
807     rc = proc_init_fs();
808     if (rc != 0) {
809         cfs_enter_debugger();
810         KdPrint(("winnt-prim.c:libcfs_arch_init: error initializing proc fs ...\n"));
811         cleanup_task_manager();
812         goto errorout;
813     }
814
815     /* initialize the tdi data */
816     rc = ks_init_tdi_data();
817     if (rc != 0) {
818         cfs_enter_debugger();
819         KdPrint(("winnt-prim.c:libcfs_arch_init: failed to initialize tdi.\n"));
820         proc_destroy_fs();
821         cleanup_task_manager();
822         goto errorout;
823     }
824
825     rc = start_shrinker_timer();
826
827 errorout:
828
829     if (rc != 0) {
830         /* destroy the taskslot cache slab */
831         if (cfs_page_t_slab) {
832             cfs_mem_cache_destroy(cfs_page_t_slab);
833         }
834         if (cfs_page_p_slab) {
835             cfs_mem_cache_destroy(cfs_page_p_slab);
836         }
837     }
838
839     return rc;
840 }
841
842 void
843 libcfs_arch_cleanup(void)
844 {
845     /* stop shrinker timer */
846     stop_shrinker_timer();
847
848     /* finialize the tdi data */
849     ks_fini_tdi_data();
850
851     /* detroy the whole proc fs tree and nodes */
852     proc_destroy_fs();
853
854     /* cleanup context of task manager */
855     cleanup_task_manager();
856
857     /* destroy the taskslot cache slab */
858     if (cfs_page_t_slab) {
859         cfs_mem_cache_destroy(cfs_page_t_slab);
860     }
861
862     if (cfs_page_p_slab) {
863         cfs_mem_cache_destroy(cfs_page_p_slab);
864     }
865
866     return;
867 }
868
869 EXPORT_SYMBOL(libcfs_arch_init);
870 EXPORT_SYMBOL(libcfs_arch_cleanup);