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.
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_kernel_thread(int (*func)(void *), void *arg, int 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_get_blockedsigs()
555 cfs_sigset_t cfs_block_allsigs()
560 cfs_sigset_t cfs_block_sigs(sigset_t bit)
565 void cfs_restore_sigs(cfs_sigset_t old)
569 int cfs_signal_pending(void)
574 void cfs_clear_sigpending(void)
580 * thread cpu affinity routines
583 typedef struct _THREAD_BASIC_INFORMATION {
585 PVOID TebBaseAddress;
587 ULONG_PTR AffinityMask;
590 } THREAD_BASIC_INFORMATION;
592 typedef THREAD_BASIC_INFORMATION *PTHREAD_BASIC_INFORMATION;
594 #define THREAD_QUERY_INFORMATION (0x0040)
600 __out PHANDLE ThreadHandle,
601 __in ACCESS_MASK DesiredAccess,
602 __in POBJECT_ATTRIBUTES ObjectAttributes,
603 __in_opt PCLIENT_ID ClientId
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
620 ZwSetInformationThread (
621 __in HANDLE ThreadHandle,
622 __in THREADINFOCLASS ThreadInformationClass,
623 __in_bcount(ThreadInformationLength) PVOID ThreadInformation,
624 __in ULONG ThreadInformationLength
628 cfs_open_current_thread()
631 HANDLE handle = NULL;
632 OBJECT_ATTRIBUTES oa;
635 /* initialize object attributes */
636 InitializeObjectAttributes( &oa, NULL, OBJ_KERNEL_HANDLE |
637 OBJ_CASE_INSENSITIVE, NULL, NULL);
639 /* initialize client id */
640 cid.UniqueProcess = PsGetCurrentProcessId();
641 cid.UniqueThread = PsGetCurrentThreadId();
643 /* get thread handle */
644 status = ZwOpenThread( &handle, THREAD_QUERY_INFORMATION |
645 THREAD_SET_INFORMATION, &oa, &cid);
646 if (!NT_SUCCESS(status)) {
654 cfs_close_thread_handle(HANDLE handle)
661 cfs_query_thread_affinity()
664 HANDLE handle = NULL;
666 THREAD_BASIC_INFORMATION TBI = {0};
668 /* open current thread */
669 handle = cfs_open_current_thread();
674 /* query thread cpu affinity */
675 status = ZwQueryInformationThread(handle, ThreadBasicInformation,
676 &TBI, sizeof(THREAD_BASIC_INFORMATION), &size);
677 if (!NT_SUCCESS(status)) {
683 cfs_close_thread_handle(handle);
684 return TBI.AffinityMask;
688 cfs_set_thread_affinity(KAFFINITY affinity)
691 HANDLE handle = NULL;
693 /* open current thread */
694 handle = cfs_open_current_thread();
699 /* set thread cpu affinity */
700 status = ZwSetInformationThread(handle, ThreadAffinityMask,
701 &affinity, sizeof(KAFFINITY));
702 if (!NT_SUCCESS(status)) {
708 cfs_close_thread_handle(handle);
709 return NT_SUCCESS(status);
713 cfs_tie_thread_to_cpu(int cpu)
715 return cfs_set_thread_affinity((KAFFINITY) (1 << cpu));
719 cfs_set_thread_priority(KPRIORITY priority)
722 HANDLE handle = NULL;
724 /* open current thread */
725 handle = cfs_open_current_thread();
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));
740 cfs_close_thread_handle(handle);
741 return NT_SUCCESS(status);
744 int cfs_need_resched(void)
749 void cfs_cond_resched(void)
754 ** Initialize routines
757 void cfs_libc_init();
760 libcfs_arch_init(void)
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);
773 /* initialize libc routines (confliction between libcnptr.lib
774 and kernel ntoskrnl.lib) */
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 );
781 cfs_page_p_slab = cfs_mem_cache_create(
782 "CPGP", CFS_PAGE_SIZE, 0, 0 );
784 if ( cfs_page_t_slab == NULL ||
785 cfs_page_p_slab == NULL ){
790 rc = init_task_manager();
792 cfs_enter_debugger();
793 KdPrint(("winnt-prim.c:libcfs_arch_init: error initializing task manager ...\n"));
797 /* initialize the proc file system */
800 cfs_enter_debugger();
801 KdPrint(("winnt-prim.c:libcfs_arch_init: error initializing proc fs ...\n"));
802 cleanup_task_manager();
806 /* initialize the tdi data */
807 rc = ks_init_tdi_data();
809 cfs_enter_debugger();
810 KdPrint(("winnt-prim.c:libcfs_arch_init: failed to initialize tdi.\n"));
812 cleanup_task_manager();
816 rc = start_shrinker_timer();
821 /* destroy the taskslot cache slab */
822 if (cfs_page_t_slab) {
823 cfs_mem_cache_destroy(cfs_page_t_slab);
825 if (cfs_page_p_slab) {
826 cfs_mem_cache_destroy(cfs_page_p_slab);
834 libcfs_arch_cleanup(void)
836 /* stop shrinker timer */
837 stop_shrinker_timer();
839 /* finialize the tdi data */
842 /* detroy the whole proc fs tree and nodes */
845 /* cleanup context of task manager */
846 cleanup_task_manager();
848 /* destroy the taskslot cache slab */
849 if (cfs_page_t_slab) {
850 cfs_mem_cache_destroy(cfs_page_t_slab);
853 if (cfs_page_p_slab) {
854 cfs_mem_cache_destroy(cfs_page_p_slab);
860 EXPORT_SYMBOL(libcfs_arch_init);
861 EXPORT_SYMBOL(libcfs_arch_cleanup);