4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21 * CA 95054 USA or visit www.sun.com if you need additional information or
27 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28 * Use is subject to license terms.
30 * Copyright (c) 2011, Whamcloud, Inc.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
37 #define DEBUG_SUBSYSTEM S_LNET
39 #include <libcfs/libcfs.h>
48 * Lustre thread procedure wrapper routine (It's an internal routine)
51 * context: a structure of cfs_thread_context_t, containing
52 * all the necessary parameters
66 cfs_thread_context_t * thread_context =
67 (cfs_thread_context_t *) context;
69 /* Execute the specified function ... */
71 if (thread_context->func) {
72 (thread_context->func)(thread_context->arg);
75 /* Free the context memory */
79 /* Terminate this system thread */
81 PsTerminateSystemThread(STATUS_SUCCESS);
86 * Create a system thread to execute the routine specified
89 * func: function to be executed in the thread
90 * arg: argument transferred to func function
91 * flag: thread creation flags.
94 * int: 0 on success or error codes
100 int cfs_create_thread(int (*func)(void *), void *arg, unsigned long flag)
102 cfs_handle_t thread = NULL;
104 cfs_thread_context_t * context = NULL;
106 /* Allocate the context to be transferred to system thread */
108 context = cfs_alloc(sizeof(cfs_thread_context_t), CFS_ALLOC_ZERO);
114 context->func = func;
117 /* Create system thread with the cfs_thread_proc wrapper */
119 status = PsCreateSystemThread(
126 if (!NT_SUCCESS(status)) {
131 /* We need translate the nt status to linux error code */
133 return cfs_error_code(status);
137 // Query the thread id of the newly created thread
151 static CFS_DECLARE_RWSEM(cfs_symbol_lock);
152 CFS_LIST_HEAD(cfs_symbol_list);
154 int libcfs_is_mp_system = FALSE;
158 * To query the specified symbol form the symbol table
161 * name: the symbol name to be queried
164 * If the symbol is in the table, return the address of it.
165 * If not, return NULL.
172 cfs_symbol_get(const char *name)
175 struct cfs_symbol *sym = NULL;
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)) {
185 cfs_up_read(&cfs_symbol_lock);
195 * To decrease the reference of the specified symbol
198 * name: the symbol name to be dereferred
208 cfs_symbol_put(const char *name)
211 struct cfs_symbol *sym = NULL;
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);
222 cfs_up_read(&cfs_symbol_lock);
224 LASSERT(sym != NULL);
229 * cfs_symbol_register
230 * To register the specified symbol infromation
233 * name: the symbol name to be dereferred
234 * value: the value that the symbol stands for
240 * Zero: Succeed to register
241 * Non-Zero: Fail to register the symbol
245 cfs_symbol_register(const char *name, const void *value)
248 struct cfs_symbol *sym = NULL;
249 struct cfs_symbol *new = NULL;
251 new = cfs_alloc(sizeof(struct cfs_symbol), CFS_ALLOC_ZERO);
255 strncpy(new->name, name, CFS_SYMBOL_LEN);
256 new->value = (void *)value;
258 CFS_INIT_LIST_HEAD(&new->sym_list);
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);
266 return 0; // alreay registerred
269 cfs_list_add_tail(&new->sym_list, &cfs_symbol_list);
270 cfs_up_write(&cfs_symbol_lock);
276 * cfs_symbol_unregister
277 * To unregister/remove the specified symbol
280 * name: the symbol name to be dereferred
290 cfs_symbol_unregister(const char *name)
294 struct cfs_symbol *sym = NULL;
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);
306 cfs_up_write(&cfs_symbol_lock);
311 * To clean all the symbols
327 struct cfs_symbol *sym = NULL;
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);
336 cfs_up_write(&cfs_symbol_lock);
347 /* Timer dpc procedure */
352 IN PVOID DeferredContext,
353 IN PVOID SystemArgument1,
354 IN PVOID SystemArgument2)
359 timer = (cfs_timer_t *) DeferredContext;
362 KeAcquireSpinLock(&(timer->Lock), &Irql);
363 cfs_clear_flag(timer->Flags, CFS_TIMER_FLAG_TIMERED);
364 KeReleaseSpinLock(&(timer->Lock), Irql);
366 /* call the user specified timer procedure */
367 timer->proc((long_ptr_t)timer->arg);
370 void cfs_init_timer(cfs_timer_t *timer)
372 memset(timer, 0, sizeof(cfs_timer_t));
377 * To initialize the cfs_timer_t
380 * timer: the cfs_timer to be initialized
381 * func: the timer callback procedure
382 * arg: argument for the callback proc
391 void cfs_timer_init(cfs_timer_t *timer, void (*func)(ulong_ptr_t), void *arg)
393 memset(timer, 0, sizeof(cfs_timer_t));
398 KeInitializeSpinLock(&(timer->Lock));
399 KeInitializeTimer(&timer->Timer);
400 KeInitializeDpc (&timer->Dpc, cfs_timer_dpc_proc, timer);
402 cfs_set_flag(timer->Flags, CFS_TIMER_FLAG_INITED);
407 * To finialize the cfs_timer_t (unused)
410 * timer: the cfs_timer to be cleaned up
419 void cfs_timer_done(cfs_timer_t *timer)
426 * To schedule the timer while touching @deadline
429 * timer: the cfs_timer to be freed
430 * dealine: timeout value to wake up the timer
439 void cfs_timer_arm(cfs_timer_t *timer, cfs_time_t deadline)
441 LARGE_INTEGER timeout;
444 KeAcquireSpinLock(&(timer->Lock), &Irql);
445 if (!cfs_is_flag_set(timer->Flags, CFS_TIMER_FLAG_TIMERED)){
447 timeout.QuadPart = (LONGLONG)-1*1000*1000*10/CFS_HZ*deadline;
449 if (KeSetTimer(&timer->Timer, timeout, &timer->Dpc)) {
450 cfs_set_flag(timer->Flags, CFS_TIMER_FLAG_TIMERED);
453 timer->deadline = deadline;
456 KeReleaseSpinLock(&(timer->Lock), Irql);
461 * To discard the timer to be scheduled
464 * timer: the cfs_timer to be discarded
473 void cfs_timer_disarm(cfs_timer_t *timer)
477 KeAcquireSpinLock(&(timer->Lock), &Irql);
478 KeCancelTimer(&(timer->Timer));
479 cfs_clear_flag(timer->Flags, CFS_TIMER_FLAG_TIMERED);
480 KeReleaseSpinLock(&(timer->Lock), Irql);
486 * To check the timer is scheduled or not
489 * timer: the cfs_timer to be checked
499 int cfs_timer_is_armed(cfs_timer_t *timer)
504 KeAcquireSpinLock(&(timer->Lock), &Irql);
505 if (cfs_is_flag_set(timer->Flags, CFS_TIMER_FLAG_TIMERED)) {
508 KeReleaseSpinLock(&(timer->Lock), Irql);
515 * To query the deadline of the timer
518 * timer: the cfs_timer to be queried
527 cfs_time_t cfs_timer_deadline(cfs_timer_t * timer)
529 return timer->deadline;
533 * daemonize routine stub
536 void cfs_daemonize(char *str)
541 int cfs_daemonize_ctxt(char *str) {
547 * routine related with sigals
550 cfs_sigset_t cfs_block_allsigs()
555 cfs_sigset_t cfs_block_sigs(sigset_t bit)
560 /* Block all signals except for the @sigs. It's only used in
561 * Linux kernel, just a dummy here. */
562 cfs_sigset_t cfs_block_sigsinv(unsigned long sigs)
567 void cfs_restore_sigs(cfs_sigset_t old)
571 int cfs_signal_pending(void)
576 void cfs_clear_sigpending(void)
582 * thread cpu affinity routines
585 typedef struct _THREAD_BASIC_INFORMATION {
587 PVOID TebBaseAddress;
589 ULONG_PTR AffinityMask;
592 } THREAD_BASIC_INFORMATION;
594 typedef THREAD_BASIC_INFORMATION *PTHREAD_BASIC_INFORMATION;
596 #define THREAD_QUERY_INFORMATION (0x0040)
602 __out PHANDLE ThreadHandle,
603 __in ACCESS_MASK DesiredAccess,
604 __in POBJECT_ATTRIBUTES ObjectAttributes,
605 __in_opt PCLIENT_ID ClientId
611 ZwQueryInformationThread (
612 __in HANDLE ThreadHandle,
613 __in THREADINFOCLASS ThreadInformationClass,
614 __out_bcount(ThreadInformationLength) PVOID ThreadInformation,
615 __in ULONG ThreadInformationLength,
616 __out_opt PULONG ReturnLength
622 ZwSetInformationThread (
623 __in HANDLE ThreadHandle,
624 __in THREADINFOCLASS ThreadInformationClass,
625 __in_bcount(ThreadInformationLength) PVOID ThreadInformation,
626 __in ULONG ThreadInformationLength
630 cfs_open_current_thread()
633 HANDLE handle = NULL;
634 OBJECT_ATTRIBUTES oa;
637 /* initialize object attributes */
638 InitializeObjectAttributes( &oa, NULL, OBJ_KERNEL_HANDLE |
639 OBJ_CASE_INSENSITIVE, NULL, NULL);
641 /* initialize client id */
642 cid.UniqueProcess = PsGetCurrentProcessId();
643 cid.UniqueThread = PsGetCurrentThreadId();
645 /* get thread handle */
646 status = ZwOpenThread( &handle, THREAD_QUERY_INFORMATION |
647 THREAD_SET_INFORMATION, &oa, &cid);
648 if (!NT_SUCCESS(status)) {
656 cfs_close_thread_handle(HANDLE handle)
663 cfs_query_thread_affinity()
666 HANDLE handle = NULL;
668 THREAD_BASIC_INFORMATION TBI = {0};
670 /* open current thread */
671 handle = cfs_open_current_thread();
676 /* query thread cpu affinity */
677 status = ZwQueryInformationThread(handle, ThreadBasicInformation,
678 &TBI, sizeof(THREAD_BASIC_INFORMATION), &size);
679 if (!NT_SUCCESS(status)) {
685 cfs_close_thread_handle(handle);
686 return TBI.AffinityMask;
690 cfs_set_thread_affinity(KAFFINITY affinity)
693 HANDLE handle = NULL;
695 /* open current thread */
696 handle = cfs_open_current_thread();
701 /* set thread cpu affinity */
702 status = ZwSetInformationThread(handle, ThreadAffinityMask,
703 &affinity, sizeof(KAFFINITY));
704 if (!NT_SUCCESS(status)) {
710 cfs_close_thread_handle(handle);
711 return NT_SUCCESS(status);
715 cfs_tie_thread_to_cpu(int cpu)
717 return cfs_set_thread_affinity((KAFFINITY) (1 << cpu));
721 cfs_set_thread_priority(KPRIORITY priority)
724 HANDLE handle = NULL;
726 /* open current thread */
727 handle = cfs_open_current_thread();
732 /* set thread cpu affinity */
733 status = ZwSetInformationThread(handle, ThreadPriority,
734 &priority, sizeof(KPRIORITY));
735 if (!NT_SUCCESS(status)) {
736 KdPrint(("set_thread_priority failed: %xh\n", status));
742 cfs_close_thread_handle(handle);
743 return NT_SUCCESS(status);
746 int cfs_need_resched(void)
751 void cfs_cond_resched(void)
756 ** Initialize routines
759 void cfs_libc_init();
762 libcfs_arch_init(void)
767 /* Workground to check the system is MP build or UP build */
768 cfs_spin_lock_init(&lock);
769 cfs_spin_lock(&lock);
770 libcfs_is_mp_system = (int)lock.lock;
771 /* MP build system: it's a real spin, for UP build system, it
772 only raises the IRQL to DISPATCH_LEVEL */
773 cfs_spin_unlock(&lock);
775 /* initialize libc routines (confliction between libcnptr.lib
776 and kernel ntoskrnl.lib) */
779 /* create slab memory caches for page alloctors */
780 cfs_page_t_slab = cfs_mem_cache_create(
781 "CPGT", sizeof(cfs_page_t), 0, 0 );
783 cfs_page_p_slab = cfs_mem_cache_create(
784 "CPGP", CFS_PAGE_SIZE, 0, 0 );
786 if ( cfs_page_t_slab == NULL ||
787 cfs_page_p_slab == NULL ){
792 rc = init_task_manager();
794 cfs_enter_debugger();
795 KdPrint(("winnt-prim.c:libcfs_arch_init: error initializing task manager ...\n"));
799 /* initialize the proc file system */
802 cfs_enter_debugger();
803 KdPrint(("winnt-prim.c:libcfs_arch_init: error initializing proc fs ...\n"));
804 cleanup_task_manager();
808 /* initialize the tdi data */
809 rc = ks_init_tdi_data();
811 cfs_enter_debugger();
812 KdPrint(("winnt-prim.c:libcfs_arch_init: failed to initialize tdi.\n"));
814 cleanup_task_manager();
818 rc = start_shrinker_timer();
823 /* destroy the taskslot cache slab */
824 if (cfs_page_t_slab) {
825 cfs_mem_cache_destroy(cfs_page_t_slab);
827 if (cfs_page_p_slab) {
828 cfs_mem_cache_destroy(cfs_page_p_slab);
836 libcfs_arch_cleanup(void)
838 /* stop shrinker timer */
839 stop_shrinker_timer();
841 /* finialize the tdi data */
844 /* detroy the whole proc fs tree and nodes */
847 /* cleanup context of task manager */
848 cleanup_task_manager();
850 /* destroy the taskslot cache slab */
851 if (cfs_page_t_slab) {
852 cfs_mem_cache_destroy(cfs_page_t_slab);
855 if (cfs_page_p_slab) {
856 cfs_mem_cache_destroy(cfs_page_p_slab);
862 EXPORT_SYMBOL(libcfs_arch_init);
863 EXPORT_SYMBOL(libcfs_arch_cleanup);