Whamcloud - gitweb
f2d321d44f9ba93f4cfbba5df2e19ddd4831846c
[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 (c) 2008, 2010, Oracle and/or its affiliates. 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 /*
580  *  thread cpu affinity routines
581  */
582
583 typedef struct _THREAD_BASIC_INFORMATION {
584     NTSTATUS ExitStatus;
585     PVOID TebBaseAddress;
586     CLIENT_ID ClientId;
587     ULONG_PTR AffinityMask;
588     KPRIORITY Priority;
589     LONG BasePriority;
590 } THREAD_BASIC_INFORMATION;
591
592 typedef THREAD_BASIC_INFORMATION *PTHREAD_BASIC_INFORMATION;
593
594 #define THREAD_QUERY_INFORMATION       (0x0040)
595
596 NTSYSAPI
597 NTSTATUS
598 NTAPI
599 ZwOpenThread (
600     __out PHANDLE ThreadHandle,
601     __in ACCESS_MASK DesiredAccess,
602     __in POBJECT_ATTRIBUTES ObjectAttributes,
603     __in_opt PCLIENT_ID ClientId
604     );
605
606 NTSYSAPI
607 NTSTATUS
608 NTAPI
609 ZwQueryInformationThread (
610     __in HANDLE ThreadHandle,
611     __in THREADINFOCLASS ThreadInformationClass,
612     __out_bcount(ThreadInformationLength) PVOID ThreadInformation,
613     __in ULONG ThreadInformationLength,
614     __out_opt PULONG ReturnLength
615     );
616
617 NTSYSAPI
618 NTSTATUS
619 NTAPI
620 ZwSetInformationThread (
621     __in HANDLE ThreadHandle,
622     __in THREADINFOCLASS ThreadInformationClass,
623     __in_bcount(ThreadInformationLength) PVOID ThreadInformation,
624     __in ULONG ThreadInformationLength
625     );
626
627 HANDLE
628 cfs_open_current_thread()
629 {
630     NTSTATUS         status;
631     HANDLE           handle = NULL;
632     OBJECT_ATTRIBUTES oa;
633     CLIENT_ID        cid;
634
635     /* initialize object attributes */
636     InitializeObjectAttributes( &oa, NULL, OBJ_KERNEL_HANDLE |
637                                 OBJ_CASE_INSENSITIVE, NULL, NULL);
638
639     /* initialize client id */
640     cid.UniqueProcess = PsGetCurrentProcessId();
641     cid.UniqueThread  = PsGetCurrentThreadId();
642
643     /* get thread handle */
644     status = ZwOpenThread( &handle, THREAD_QUERY_INFORMATION |
645                            THREAD_SET_INFORMATION, &oa, &cid);
646     if (!NT_SUCCESS(status)) {
647         handle = NULL;
648     }
649
650     return handle;
651 }
652
653 void
654 cfs_close_thread_handle(HANDLE handle)
655 {
656     if (handle)
657         ZwClose(handle);
658 }
659
660 KAFFINITY
661 cfs_query_thread_affinity()
662 {
663     NTSTATUS         status;
664     HANDLE           handle = NULL;
665     DWORD            size;
666     THREAD_BASIC_INFORMATION TBI = {0};
667
668     /* open current thread */
669     handle = cfs_open_current_thread();
670     if (!handle) {
671         goto errorout;
672     }
673
674     /* query thread cpu affinity */
675     status = ZwQueryInformationThread(handle, ThreadBasicInformation,
676                        &TBI, sizeof(THREAD_BASIC_INFORMATION), &size);
677     if (!NT_SUCCESS(status)) {
678         goto errorout;
679     }
680
681 errorout:
682
683     cfs_close_thread_handle(handle);
684     return TBI.AffinityMask;
685 }
686
687 int
688 cfs_set_thread_affinity(KAFFINITY affinity)
689 {
690     NTSTATUS         status;
691     HANDLE           handle = NULL;
692
693     /* open current thread */
694     handle = cfs_open_current_thread();
695     if (!handle) {
696         goto errorout;
697     }
698
699     /* set thread cpu affinity */
700     status = ZwSetInformationThread(handle, ThreadAffinityMask,
701                                     &affinity, sizeof(KAFFINITY));
702     if (!NT_SUCCESS(status)) {
703         goto errorout;
704     }
705
706 errorout:
707
708     cfs_close_thread_handle(handle);
709     return NT_SUCCESS(status);
710 }
711
712 int
713 cfs_tie_thread_to_cpu(int cpu)
714 {
715     return cfs_set_thread_affinity((KAFFINITY) (1 << cpu));
716 }
717
718 int
719 cfs_set_thread_priority(KPRIORITY priority)
720 {
721     NTSTATUS         status;
722     HANDLE           handle = NULL;
723
724     /* open current thread */
725     handle = cfs_open_current_thread();
726     if (!handle) {
727         goto errorout;
728     }
729
730     /* set thread cpu affinity */
731     status = ZwSetInformationThread(handle, ThreadPriority,
732                                     &priority, sizeof(KPRIORITY));
733     if (!NT_SUCCESS(status)) {
734         KdPrint(("set_thread_priority failed: %xh\n", status));
735         goto errorout;
736     }
737
738 errorout:
739
740     cfs_close_thread_handle(handle);
741     return NT_SUCCESS(status);
742 }
743
744 int cfs_need_resched(void)
745 {
746         return 0;
747 }
748
749 void cfs_cond_resched(void)
750 {
751 }
752
753 /**
754  **  Initialize routines
755  **/
756
757 void cfs_libc_init();
758
759 int
760 libcfs_arch_init(void)
761 {
762     int         rc;
763
764     cfs_spinlock_t  lock;
765     /* Workground to check the system is MP build or UP build */
766     cfs_spin_lock_init(&lock);
767     cfs_spin_lock(&lock);
768     libcfs_is_mp_system = (int)lock.lock;
769     /* MP build system: it's a real spin, for UP build system, it
770        only raises the IRQL to DISPATCH_LEVEL */
771     cfs_spin_unlock(&lock);
772
773     /* initialize libc routines (confliction between libcnptr.lib
774        and kernel ntoskrnl.lib) */
775     cfs_libc_init();
776
777     /* create slab memory caches for page alloctors */
778     cfs_page_t_slab = cfs_mem_cache_create(
779         "CPGT", sizeof(cfs_page_t), 0, 0 );
780
781     cfs_page_p_slab = cfs_mem_cache_create(
782         "CPGP", CFS_PAGE_SIZE, 0, 0 );
783
784     if ( cfs_page_t_slab == NULL ||
785          cfs_page_p_slab == NULL ){
786         rc = -ENOMEM;
787         goto errorout;
788     }
789
790     rc = init_task_manager();
791     if (rc != 0) {
792         cfs_enter_debugger();
793         KdPrint(("winnt-prim.c:libcfs_arch_init: error initializing task manager ...\n"));
794         goto errorout;
795     }
796
797     /* initialize the proc file system */
798     rc = proc_init_fs();
799     if (rc != 0) {
800         cfs_enter_debugger();
801         KdPrint(("winnt-prim.c:libcfs_arch_init: error initializing proc fs ...\n"));
802         cleanup_task_manager();
803         goto errorout;
804     }
805
806     /* initialize the tdi data */
807     rc = ks_init_tdi_data();
808     if (rc != 0) {
809         cfs_enter_debugger();
810         KdPrint(("winnt-prim.c:libcfs_arch_init: failed to initialize tdi.\n"));
811         proc_destroy_fs();
812         cleanup_task_manager();
813         goto errorout;
814     }
815
816     rc = start_shrinker_timer();
817
818 errorout:
819
820     if (rc != 0) {
821         /* destroy the taskslot cache slab */
822         if (cfs_page_t_slab) {
823             cfs_mem_cache_destroy(cfs_page_t_slab);
824         }
825         if (cfs_page_p_slab) {
826             cfs_mem_cache_destroy(cfs_page_p_slab);
827         }
828     }
829
830     return rc;
831 }
832
833 void
834 libcfs_arch_cleanup(void)
835 {
836     /* stop shrinker timer */
837     stop_shrinker_timer();
838
839     /* finialize the tdi data */
840     ks_fini_tdi_data();
841
842     /* detroy the whole proc fs tree and nodes */
843     proc_destroy_fs();
844
845     /* cleanup context of task manager */
846     cleanup_task_manager();
847
848     /* destroy the taskslot cache slab */
849     if (cfs_page_t_slab) {
850         cfs_mem_cache_destroy(cfs_page_t_slab);
851     }
852
853     if (cfs_page_p_slab) {
854         cfs_mem_cache_destroy(cfs_page_p_slab);
855     }
856
857     return;
858 }
859
860 EXPORT_SYMBOL(libcfs_arch_init);
861 EXPORT_SYMBOL(libcfs_arch_cleanup);