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, 2012, Intel Corporation.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
36 * libcfs/libcfs/darwin/darwin-prim.c
38 * Darwin porting library
39 * Make things easy to port
41 * Author: Phil Schwan <phil@clusterfs.com>
44 #define DEBUG_SUBSYSTEM S_LNET
46 #include <mach/mach_types.h>
51 #include <sys/filedesc.h>
52 #include <sys/namei.h>
53 #include <miscfs/devfs/devfs.h>
54 #include <kern/thread.h>
56 #include <libcfs/libcfs.h>
59 * cfs pseudo device, actually pseudo char device in darwin
61 #define KLNET_MAJOR -1
63 kern_return_t misc_register(struct miscdevice *dev) {
64 dev->index = cdevsw_add(KLNET_MAJOR, dev->devsw);
66 printf("libcfs_init: failed to allocate a major number!\n");
69 dev->handle = devfs_make_node(makedev (dev->index, 0),
71 GID_WHEEL, 0666, (char *)dev->name, 0);
75 kern_return_t misc_deregister(struct miscdevice *dev) {
76 devfs_remove(dev->handle);
77 cdevsw_remove(dev->index, dev->devsw);
82 * KPortal symbol register / unregister support
84 struct rw_semaphore cfs_symbol_lock;
85 struct list_head cfs_symbol_list;
88 cfs_symbol_get(const char *name)
90 struct list_head *walker;
91 struct cfs_symbol *sym = NULL;
93 down_read(&cfs_symbol_lock);
94 list_for_each(walker, &cfs_symbol_list) {
95 sym = list_entry (walker, struct cfs_symbol, sym_list);
96 if (!strcmp(sym->name, name)) {
101 up_read(&cfs_symbol_lock);
108 cfs_symbol_put(const char *name)
110 struct list_head *walker;
111 struct cfs_symbol *sym = NULL;
113 down_read(&cfs_symbol_lock);
114 list_for_each(walker, &cfs_symbol_list) {
115 sym = list_entry (walker, struct cfs_symbol, sym_list);
116 if (!strcmp(sym->name, name)) {
118 LASSERT(sym->ref >= 0);
122 up_read(&cfs_symbol_lock);
123 LASSERT(sym != NULL);
129 cfs_symbol_register(const char *name, const void *value)
131 struct list_head *walker;
132 struct cfs_symbol *sym = NULL;
133 struct cfs_symbol *new = NULL;
135 MALLOC(new, struct cfs_symbol *, sizeof(struct cfs_symbol), M_TEMP, M_WAITOK|M_ZERO);
136 strncpy(new->name, name, CFS_SYMBOL_LEN);
137 new->value = (void *)value;
139 INIT_LIST_HEAD(&new->sym_list);
141 down_write(&cfs_symbol_lock);
142 list_for_each(walker, &cfs_symbol_list) {
143 sym = list_entry (walker, struct cfs_symbol, sym_list);
144 if (!strcmp(sym->name, name)) {
145 up_write(&cfs_symbol_lock);
147 return KERN_NAME_EXISTS;
150 list_add_tail(&new->sym_list, &cfs_symbol_list);
151 up_write(&cfs_symbol_lock);
156 cfs_symbol_unregister(const char *name)
158 struct list_head *walker;
159 struct list_head *nxt;
160 struct cfs_symbol *sym = NULL;
162 down_write(&cfs_symbol_lock);
163 list_for_each_safe(walker, nxt, &cfs_symbol_list) {
164 sym = list_entry(walker, struct cfs_symbol, sym_list);
165 if (!strcmp(sym->name, name)) {
166 LASSERT(sym->ref == 0);
167 list_del(&sym->sym_list);
172 up_write(&cfs_symbol_lock);
180 INIT_LIST_HEAD(&cfs_symbol_list);
181 init_rwsem(&cfs_symbol_lock);
187 struct list_head *walker;
188 struct cfs_symbol *sym = NULL;
190 down_write(&cfs_symbol_lock);
191 list_for_each(walker, &cfs_symbol_list) {
192 sym = list_entry(walker, struct cfs_symbol, sym_list);
193 LASSERT(sym->ref == 0);
194 list_del(&sym->sym_list);
197 up_write(&cfs_symbol_lock);
199 fini_rwsem(&cfs_symbol_lock);
203 struct kernel_thread_arg
211 struct kernel_thread_arg cfs_thread_arg;
213 #define THREAD_ARG_FREE 0
214 #define THREAD_ARG_HOLD 1
215 #define THREAD_ARG_RECV 2
217 #define set_targ_stat(a, v) atomic_set(&(a)->inuse, v)
218 #define get_targ_stat(a) atomic_read(&(a)->inuse)
221 * Hold the thread argument and set the status of thread_status
222 * to THREAD_ARG_HOLD, if the thread argument is held by other
223 * threads (It's THREAD_ARG_HOLD already), current-thread has to wait.
225 #define thread_arg_hold(pta, _func, _arg) \
227 spin_lock(&(pta)->lock); \
228 if (get_targ_stat(pta) == THREAD_ARG_FREE) { \
229 set_targ_stat((pta), THREAD_ARG_HOLD); \
230 (pta)->arg = (void *)_arg; \
231 (pta)->func = _func; \
232 spin_unlock(&(pta)->lock); \
235 spin_unlock(&(pta)->lock); \
240 * Release the thread argument if the thread argument has been
241 * received by the child-thread (Status of thread_args is
242 * THREAD_ARG_RECV), otherwise current-thread has to wait.
243 * After release, the thread_args' status will be set to
244 * THREAD_ARG_FREE, and others can re-use the thread_args to
245 * create new kernel_thread.
247 #define thread_arg_release(pta) \
249 spin_lock(&(pta)->lock); \
250 if (get_targ_stat(pta) == THREAD_ARG_RECV) { \
252 (pta)->func = NULL; \
253 set_targ_stat(pta, THREAD_ARG_FREE); \
254 spin_unlock(&(pta)->lock); \
257 spin_unlock(&(pta)->lock); \
262 * Receive thread argument (Used in child thread), set the status
263 * of thread_args to THREAD_ARG_RECV.
265 #define __thread_arg_recv_fin(pta, _func, _arg, fin) \
267 spin_lock(&(pta)->lock); \
268 if (get_targ_stat(pta) == THREAD_ARG_HOLD) { \
270 set_targ_stat(pta, THREAD_ARG_RECV);\
272 _func = (pta)->func; \
273 spin_unlock(&(pta)->lock); \
276 spin_unlock(&(pta)->lock); \
281 * Just set the thread_args' status to THREAD_ARG_RECV
283 #define thread_arg_fin(pta) \
285 spin_lock(&(pta)->lock); \
286 assert( get_targ_stat(pta) == THREAD_ARG_HOLD); \
287 set_targ_stat(pta, THREAD_ARG_RECV); \
288 spin_unlock(&(pta)->lock); \
291 #define thread_arg_recv(pta, f, a) __thread_arg_recv_fin(pta, f, a, 1)
292 #define thread_arg_keep(pta, f, a) __thread_arg_recv_fin(pta, f, a, 0)
295 cfs_thread_agent_init(void)
297 set_targ_stat(&cfs_thread_arg, THREAD_ARG_FREE);
298 spin_lock_init(&cfs_thread_arg.lock);
299 cfs_thread_arg.arg = NULL;
300 cfs_thread_arg.func = NULL;
304 cfs_thread_agent_fini(void)
306 assert(get_targ_stat(&cfs_thread_arg) == THREAD_ARG_FREE);
308 spin_lock_done(&cfs_thread_arg.lock);
313 * All requests to create kernel thread will create a new
314 * thread instance of cfs_thread_agent, one by one.
315 * cfs_thread_agent will call the caller's thread function
316 * with argument supplied by caller.
319 cfs_thread_agent (void)
321 cfs_thread_t func = NULL;
324 thread_arg_recv(&cfs_thread_arg, func, arg);
325 /* printf("entry of thread agent (func: %08lx).\n", (void *)func); */
326 assert(func != NULL);
328 /* printf("thread agent exit. (func: %08lx)\n", (void *)func); */
329 (void) thread_terminate(current_thread());
332 extern thread_t kernel_thread(task_t task, void (*start)(void));
335 kthread_run(cfs_thread_t func, void *arg, const char namefmt[], ...)
340 thread_arg_hold(&cfs_thread_arg, func, arg);
341 th = kernel_thread(kernel_task, cfs_thread_agent);
342 thread_arg_release(&cfs_thread_arg);
343 if (th != THREAD_NULL) {
345 * FIXME: change child thread name...
346 * current_comm() is already broken. So it is left as is...
348 va_start(args, namefmt);
349 snprintf(current_comm(), CFS_CURPROC_COMM_MAX,
356 return (struct task_struct)((long)ret);
360 * XXX Liang: kexts cannot access sigmask in Darwin8.
361 * it's almost impossible for us to get/set signal mask
362 * without patching kernel.
363 * Should we provide these functions in xnu?
365 * These signal functions almost do nothing now, we
366 * need to investigate more about signal in Darwin.
369 extern int block_procsigmask(struct proc *p, int bit);
371 sigset_t cfs_block_allsigs()
376 block_procsigmask(current_proc(), -1);
381 sigset_t cfs_block_sigs(unsigned long sigs)
386 block_procsigmask(current_proc(), sigs);
391 /* Block all signals except for the @sigs. It's only used in
392 * Linux kernel, just a dummy here. */
393 sigset_t cfs_block_sigsinv(unsigned long sigs)
399 void cfs_restore_sigs(sigset_t old)
403 int cfs_signal_pending(void)
407 extern int thread_issignal(proc_t, thread_t, sigset_t);
408 return thread_issignal(current_proc(), current_thread(), (sigset_t)-1);
410 return SHOULDissignal(current_proc(), current_uthread())
414 void cfs_clear_sigpending(void)
418 clear_procsiglist(current_proc(), -1);
424 #else /* !__DARWIN8__ */
426 void lustre_cone_in(boolean_t *state, funnel_t **cone)
428 *cone = thread_funnel_get();
429 if (*cone == network_flock)
430 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
431 else if (*cone == NULL)
432 *state = thread_funnel_set(kernel_flock, TRUE);
435 void lustre_cone_ex(boolean_t state, funnel_t *cone)
437 if (cone == network_flock)
438 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
439 else if (cone == NULL)
440 (void) thread_funnel_set(kernel_flock, state);
443 void lustre_net_in(boolean_t *state, funnel_t **cone)
445 *cone = thread_funnel_get();
446 if (*cone == kernel_flock)
447 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
448 else if (*cone == NULL)
449 *state = thread_funnel_set(network_flock, TRUE);
452 void lustre_net_ex(boolean_t state, funnel_t *cone)
454 if (cone == kernel_flock)
455 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
456 else if (cone == NULL)
457 (void) thread_funnel_set(network_flock, state);
459 #endif /* !__DARWIN8__ */
461 void init_waitqueue_head(struct cfs_waitq *waitq)
463 ksleep_chan_init(&waitq->wq_ksleep_chan);
466 void init_waitqueue_entry_current(struct cfs_waitlink *link)
468 ksleep_link_init(&link->wl_ksleep_link);
471 void add_wait_queue(struct cfs_waitq *waitq, struct cfs_waitlink *link)
473 link->wl_waitq = waitq;
474 ksleep_add(&waitq->wq_ksleep_chan, &link->wl_ksleep_link);
477 void add_wait_queue_exclusive(struct cfs_waitq *waitq,
478 struct cfs_waitlink *link)
480 link->wl_waitq = waitq;
481 link->wl_ksleep_link.flags |= KSLEEP_EXCLUSIVE;
482 ksleep_add(&waitq->wq_ksleep_chan, &link->wl_ksleep_link);
485 void remove_wait_queue(struct cfs_waitq *waitq,
486 struct cfs_waitlink *link)
488 ksleep_del(&waitq->wq_ksleep_chan, &link->wl_ksleep_link);
491 int waitqueue_active(struct cfs_waitq *waitq)
496 void wake_up(struct cfs_waitq *waitq)
499 * XXX nikita: do NOT call libcfs_debug_msg() (CDEBUG/ENTRY/EXIT)
500 * from here: this will lead to infinite recursion.
502 ksleep_wake(&waitq->wq_ksleep_chan);
505 void wake_up_nr(struct cfs_waitq *waitq, int nr)
507 ksleep_wake_nr(&waitq->wq_ksleep_chan, nr);
510 void wake_up_all(struct cfs_waitq *waitq)
512 ksleep_wake_all(&waitq->wq_ksleep_chan);
515 void waitq_wait(struct cfs_waitlink *link, long state)
517 ksleep_wait(&link->wl_waitq->wq_ksleep_chan, state);
520 cfs_duration_t waitq_timedwait(struct cfs_waitlink *link,
522 cfs_duration_t timeout)
524 return ksleep_timedwait(&link->wl_waitq->wq_ksleep_chan,
528 typedef void (*ktimer_func_t)(void *);
529 void cfs_timer_init(struct timer_list *t, void (* func)(unsigned long), void *arg)
531 ktimer_init(&t->t, (ktimer_func_t)func, arg);
534 void cfs_timer_done(struct cfs_timer *t)
539 void cfs_timer_arm(struct cfs_timer *t, cfs_time_t deadline)
541 ktimer_arm(&t->t, deadline);
544 void cfs_timer_disarm(struct cfs_timer *t)
546 ktimer_disarm(&t->t);
549 int cfs_timer_is_armed(struct cfs_timer *t)
551 return ktimer_is_armed(&t->t);
554 cfs_time_t cfs_timer_deadline(struct cfs_timer *t)
556 return ktimer_deadline(&t->t);
559 void cfs_enter_debugger(void)
562 extern void Debugger(const char * reason);
565 extern void PE_enter_debugger(char *cause);
566 PE_enter_debugger("CFS");
570 int cfs_online_cpus(void)
577 sysctlbyname("hw.activecpu", &activecpu, &size, NULL, 0);
580 host_basic_info_data_t hinfo;
582 int count = HOST_BASIC_INFO_COUNT;
584 kret = host_info(BSD_HOST, HOST_BASIC_INFO, &hinfo, &count);
585 if (kret == KERN_SUCCESS)
586 return (hinfo.avail_cpus);
598 sysctlbyname("hw.ncpu", &ncpu, &size, NULL, 0);