1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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
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
29 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
30 * Use is subject to license terms.
32 * Copyright (c) 2011, Whamcloud, Inc.
35 * This file is part of Lustre, http://www.lustre.org/
36 * Lustre is a trademark of Sun Microsystems, Inc.
39 #define DEBUG_SUBSYSTEM S_LNET
41 #include <libcfs/libcfs.h>
50 * Lustre thread procedure wrapper routine (It's an internal routine)
53 * context: a structure of cfs_thread_context_t, containing
54 * all the necessary parameters
68 cfs_thread_context_t * thread_context =
69 (cfs_thread_context_t *) context;
71 /* Execute the specified function ... */
73 if (thread_context->func) {
74 (thread_context->func)(thread_context->arg);
77 /* Free the context memory */
81 /* Terminate this system thread */
83 PsTerminateSystemThread(STATUS_SUCCESS);
88 * Create a system thread to execute the routine specified
91 * func: function to be executed in the thread
92 * arg: argument transferred to func function
93 * flag: thread creation flags.
96 * int: 0 on success or error codes
102 int cfs_create_thread(int (*func)(void *), void *arg, unsigned long flag)
104 cfs_handle_t thread = NULL;
106 cfs_thread_context_t * context = NULL;
108 /* Allocate the context to be transferred to system thread */
110 context = cfs_alloc(sizeof(cfs_thread_context_t), CFS_ALLOC_ZERO);
116 context->func = func;
119 /* Create system thread with the cfs_thread_proc wrapper */
121 status = PsCreateSystemThread(
128 if (!NT_SUCCESS(status)) {
133 /* We need translate the nt status to linux error code */
135 return cfs_error_code(status);
139 // Query the thread id of the newly created thread
153 static CFS_DECLARE_RWSEM(cfs_symbol_lock);
154 CFS_LIST_HEAD(cfs_symbol_list);
156 int libcfs_is_mp_system = FALSE;
160 * To query the specified symbol form the symbol table
163 * name: the symbol name to be queried
166 * If the symbol is in the table, return the address of it.
167 * If not, return NULL.
174 cfs_symbol_get(const char *name)
177 struct cfs_symbol *sym = NULL;
179 cfs_down_read(&cfs_symbol_lock);
180 cfs_list_for_each(walker, &cfs_symbol_list) {
181 sym = cfs_list_entry (walker, struct cfs_symbol, sym_list);
182 if (!strcmp(sym->name, name)) {
187 cfs_up_read(&cfs_symbol_lock);
197 * To decrease the reference of the specified symbol
200 * name: the symbol name to be dereferred
210 cfs_symbol_put(const char *name)
213 struct cfs_symbol *sym = NULL;
215 cfs_down_read(&cfs_symbol_lock);
216 cfs_list_for_each(walker, &cfs_symbol_list) {
217 sym = cfs_list_entry (walker, struct cfs_symbol, sym_list);
218 if (!strcmp(sym->name, name)) {
219 LASSERT(sym->ref > 0);
224 cfs_up_read(&cfs_symbol_lock);
226 LASSERT(sym != NULL);
231 * cfs_symbol_register
232 * To register the specified symbol infromation
235 * name: the symbol name to be dereferred
236 * value: the value that the symbol stands for
242 * Zero: Succeed to register
243 * Non-Zero: Fail to register the symbol
247 cfs_symbol_register(const char *name, const void *value)
250 struct cfs_symbol *sym = NULL;
251 struct cfs_symbol *new = NULL;
253 new = cfs_alloc(sizeof(struct cfs_symbol), CFS_ALLOC_ZERO);
257 strncpy(new->name, name, CFS_SYMBOL_LEN);
258 new->value = (void *)value;
260 CFS_INIT_LIST_HEAD(&new->sym_list);
262 cfs_down_write(&cfs_symbol_lock);
263 cfs_list_for_each(walker, &cfs_symbol_list) {
264 sym = cfs_list_entry (walker, struct cfs_symbol, sym_list);
265 if (!strcmp(sym->name, name)) {
266 cfs_up_write(&cfs_symbol_lock);
268 return 0; // alreay registerred
271 cfs_list_add_tail(&new->sym_list, &cfs_symbol_list);
272 cfs_up_write(&cfs_symbol_lock);
278 * cfs_symbol_unregister
279 * To unregister/remove the specified symbol
282 * name: the symbol name to be dereferred
292 cfs_symbol_unregister(const char *name)
296 struct cfs_symbol *sym = NULL;
298 cfs_down_write(&cfs_symbol_lock);
299 cfs_list_for_each_safe(walker, nxt, &cfs_symbol_list) {
300 sym = cfs_list_entry (walker, struct cfs_symbol, sym_list);
301 if (!strcmp(sym->name, name)) {
302 LASSERT(sym->ref == 0);
303 cfs_list_del (&sym->sym_list);
308 cfs_up_write(&cfs_symbol_lock);
313 * To clean all the symbols
329 struct cfs_symbol *sym = NULL;
331 cfs_down_write(&cfs_symbol_lock);
332 cfs_list_for_each(walker, &cfs_symbol_list) {
333 sym = cfs_list_entry (walker, struct cfs_symbol, sym_list);
334 LASSERT(sym->ref == 0);
335 cfs_list_del (&sym->sym_list);
338 cfs_up_write(&cfs_symbol_lock);
349 /* Timer dpc procedure */
354 IN PVOID DeferredContext,
355 IN PVOID SystemArgument1,
356 IN PVOID SystemArgument2)
361 timer = (cfs_timer_t *) DeferredContext;
364 KeAcquireSpinLock(&(timer->Lock), &Irql);
365 cfs_clear_flag(timer->Flags, CFS_TIMER_FLAG_TIMERED);
366 KeReleaseSpinLock(&(timer->Lock), Irql);
368 /* call the user specified timer procedure */
369 timer->proc((long_ptr_t)timer->arg);
372 void cfs_init_timer(cfs_timer_t *timer)
374 memset(timer, 0, sizeof(cfs_timer_t));
379 * To initialize the cfs_timer_t
382 * timer: the cfs_timer to be initialized
383 * func: the timer callback procedure
384 * arg: argument for the callback proc
393 void cfs_timer_init(cfs_timer_t *timer, void (*func)(ulong_ptr_t), void *arg)
395 memset(timer, 0, sizeof(cfs_timer_t));
400 KeInitializeSpinLock(&(timer->Lock));
401 KeInitializeTimer(&timer->Timer);
402 KeInitializeDpc (&timer->Dpc, cfs_timer_dpc_proc, timer);
404 cfs_set_flag(timer->Flags, CFS_TIMER_FLAG_INITED);
409 * To finialize the cfs_timer_t (unused)
412 * timer: the cfs_timer to be cleaned up
421 void cfs_timer_done(cfs_timer_t *timer)
428 * To schedule the timer while touching @deadline
431 * timer: the cfs_timer to be freed
432 * dealine: timeout value to wake up the timer
441 void cfs_timer_arm(cfs_timer_t *timer, cfs_time_t deadline)
443 LARGE_INTEGER timeout;
446 KeAcquireSpinLock(&(timer->Lock), &Irql);
447 if (!cfs_is_flag_set(timer->Flags, CFS_TIMER_FLAG_TIMERED)){
449 timeout.QuadPart = (LONGLONG)-1*1000*1000*10/CFS_HZ*deadline;
451 if (KeSetTimer(&timer->Timer, timeout, &timer->Dpc)) {
452 cfs_set_flag(timer->Flags, CFS_TIMER_FLAG_TIMERED);
455 timer->deadline = deadline;
458 KeReleaseSpinLock(&(timer->Lock), Irql);
463 * To discard the timer to be scheduled
466 * timer: the cfs_timer to be discarded
475 void cfs_timer_disarm(cfs_timer_t *timer)
479 KeAcquireSpinLock(&(timer->Lock), &Irql);
480 KeCancelTimer(&(timer->Timer));
481 cfs_clear_flag(timer->Flags, CFS_TIMER_FLAG_TIMERED);
482 KeReleaseSpinLock(&(timer->Lock), Irql);
488 * To check the timer is scheduled or not
491 * timer: the cfs_timer to be checked
501 int cfs_timer_is_armed(cfs_timer_t *timer)
506 KeAcquireSpinLock(&(timer->Lock), &Irql);
507 if (cfs_is_flag_set(timer->Flags, CFS_TIMER_FLAG_TIMERED)) {
510 KeReleaseSpinLock(&(timer->Lock), Irql);
517 * To query the deadline of the timer
520 * timer: the cfs_timer to be queried
529 cfs_time_t cfs_timer_deadline(cfs_timer_t * timer)
531 return timer->deadline;
535 * daemonize routine stub
538 void cfs_daemonize(char *str)
543 int cfs_daemonize_ctxt(char *str) {
549 * routine related with sigals
552 cfs_sigset_t cfs_block_allsigs()
557 cfs_sigset_t cfs_block_sigs(sigset_t bit)
562 /* Block all signals except for the @sigs. It's only used in
563 * Linux kernel, just a dummy here. */
564 cfs_sigset_t cfs_block_sigsinv(unsigned long sigs)
569 void cfs_restore_sigs(cfs_sigset_t old)
573 int cfs_signal_pending(void)
578 void cfs_clear_sigpending(void)
584 * thread cpu affinity routines
587 typedef struct _THREAD_BASIC_INFORMATION {
589 PVOID TebBaseAddress;
591 ULONG_PTR AffinityMask;
594 } THREAD_BASIC_INFORMATION;
596 typedef THREAD_BASIC_INFORMATION *PTHREAD_BASIC_INFORMATION;
598 #define THREAD_QUERY_INFORMATION (0x0040)
604 __out PHANDLE ThreadHandle,
605 __in ACCESS_MASK DesiredAccess,
606 __in POBJECT_ATTRIBUTES ObjectAttributes,
607 __in_opt PCLIENT_ID ClientId
613 ZwQueryInformationThread (
614 __in HANDLE ThreadHandle,
615 __in THREADINFOCLASS ThreadInformationClass,
616 __out_bcount(ThreadInformationLength) PVOID ThreadInformation,
617 __in ULONG ThreadInformationLength,
618 __out_opt PULONG ReturnLength
624 ZwSetInformationThread (
625 __in HANDLE ThreadHandle,
626 __in THREADINFOCLASS ThreadInformationClass,
627 __in_bcount(ThreadInformationLength) PVOID ThreadInformation,
628 __in ULONG ThreadInformationLength
632 cfs_open_current_thread()
635 HANDLE handle = NULL;
636 OBJECT_ATTRIBUTES oa;
639 /* initialize object attributes */
640 InitializeObjectAttributes( &oa, NULL, OBJ_KERNEL_HANDLE |
641 OBJ_CASE_INSENSITIVE, NULL, NULL);
643 /* initialize client id */
644 cid.UniqueProcess = PsGetCurrentProcessId();
645 cid.UniqueThread = PsGetCurrentThreadId();
647 /* get thread handle */
648 status = ZwOpenThread( &handle, THREAD_QUERY_INFORMATION |
649 THREAD_SET_INFORMATION, &oa, &cid);
650 if (!NT_SUCCESS(status)) {
658 cfs_close_thread_handle(HANDLE handle)
665 cfs_query_thread_affinity()
668 HANDLE handle = NULL;
670 THREAD_BASIC_INFORMATION TBI = {0};
672 /* open current thread */
673 handle = cfs_open_current_thread();
678 /* query thread cpu affinity */
679 status = ZwQueryInformationThread(handle, ThreadBasicInformation,
680 &TBI, sizeof(THREAD_BASIC_INFORMATION), &size);
681 if (!NT_SUCCESS(status)) {
687 cfs_close_thread_handle(handle);
688 return TBI.AffinityMask;
692 cfs_set_thread_affinity(KAFFINITY affinity)
695 HANDLE handle = NULL;
697 /* open current thread */
698 handle = cfs_open_current_thread();
703 /* set thread cpu affinity */
704 status = ZwSetInformationThread(handle, ThreadAffinityMask,
705 &affinity, sizeof(KAFFINITY));
706 if (!NT_SUCCESS(status)) {
712 cfs_close_thread_handle(handle);
713 return NT_SUCCESS(status);
717 cfs_tie_thread_to_cpu(int cpu)
719 return cfs_set_thread_affinity((KAFFINITY) (1 << cpu));
723 cfs_set_thread_priority(KPRIORITY priority)
726 HANDLE handle = NULL;
728 /* open current thread */
729 handle = cfs_open_current_thread();
734 /* set thread cpu affinity */
735 status = ZwSetInformationThread(handle, ThreadPriority,
736 &priority, sizeof(KPRIORITY));
737 if (!NT_SUCCESS(status)) {
738 KdPrint(("set_thread_priority failed: %xh\n", status));
744 cfs_close_thread_handle(handle);
745 return NT_SUCCESS(status);
748 int cfs_need_resched(void)
753 void cfs_cond_resched(void)
758 ** Initialize routines
761 void cfs_libc_init();
764 libcfs_arch_init(void)
769 /* Workground to check the system is MP build or UP build */
770 cfs_spin_lock_init(&lock);
771 cfs_spin_lock(&lock);
772 libcfs_is_mp_system = (int)lock.lock;
773 /* MP build system: it's a real spin, for UP build system, it
774 only raises the IRQL to DISPATCH_LEVEL */
775 cfs_spin_unlock(&lock);
777 /* initialize libc routines (confliction between libcnptr.lib
778 and kernel ntoskrnl.lib) */
781 /* create slab memory caches for page alloctors */
782 cfs_page_t_slab = cfs_mem_cache_create(
783 "CPGT", sizeof(cfs_page_t), 0, 0 );
785 cfs_page_p_slab = cfs_mem_cache_create(
786 "CPGP", CFS_PAGE_SIZE, 0, 0 );
788 if ( cfs_page_t_slab == NULL ||
789 cfs_page_p_slab == NULL ){
794 rc = init_task_manager();
796 cfs_enter_debugger();
797 KdPrint(("winnt-prim.c:libcfs_arch_init: error initializing task manager ...\n"));
801 /* initialize the proc file system */
804 cfs_enter_debugger();
805 KdPrint(("winnt-prim.c:libcfs_arch_init: error initializing proc fs ...\n"));
806 cleanup_task_manager();
810 /* initialize the tdi data */
811 rc = ks_init_tdi_data();
813 cfs_enter_debugger();
814 KdPrint(("winnt-prim.c:libcfs_arch_init: failed to initialize tdi.\n"));
816 cleanup_task_manager();
820 rc = start_shrinker_timer();
825 /* destroy the taskslot cache slab */
826 if (cfs_page_t_slab) {
827 cfs_mem_cache_destroy(cfs_page_t_slab);
829 if (cfs_page_p_slab) {
830 cfs_mem_cache_destroy(cfs_page_p_slab);
838 libcfs_arch_cleanup(void)
840 /* stop shrinker timer */
841 stop_shrinker_timer();
843 /* finialize the tdi data */
846 /* detroy the whole proc fs tree and nodes */
849 /* cleanup context of task manager */
850 cleanup_task_manager();
852 /* destroy the taskslot cache slab */
853 if (cfs_page_t_slab) {
854 cfs_mem_cache_destroy(cfs_page_t_slab);
857 if (cfs_page_p_slab) {
858 cfs_mem_cache_destroy(cfs_page_p_slab);
864 EXPORT_SYMBOL(libcfs_arch_init);
865 EXPORT_SYMBOL(libcfs_arch_cleanup);