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.
38 * libcfs/libcfs/darwin/darwin-prim.c
40 * Darwin porting library
41 * Make things easy to port
43 * Author: Phil Schwan <phil@clusterfs.com>
46 #define DEBUG_SUBSYSTEM S_LNET
48 #include <mach/mach_types.h>
53 #include <sys/filedesc.h>
54 #include <sys/namei.h>
55 #include <miscfs/devfs/devfs.h>
56 #include <kern/thread.h>
58 #include <libcfs/libcfs.h>
61 * cfs pseudo device, actually pseudo char device in darwin
63 #define KLNET_MAJOR -1
65 kern_return_t cfs_psdev_register(cfs_psdev_t *dev) {
66 dev->index = cdevsw_add(KLNET_MAJOR, dev->devsw);
68 printf("libcfs_init: failed to allocate a major number!\n");
71 dev->handle = devfs_make_node(makedev (dev->index, 0),
73 GID_WHEEL, 0666, (char *)dev->name, 0);
77 kern_return_t cfs_psdev_deregister(cfs_psdev_t *dev) {
78 devfs_remove(dev->handle);
79 cdevsw_remove(dev->index, dev->devsw);
84 * KPortal symbol register / unregister support
86 struct rw_semaphore cfs_symbol_lock;
87 struct list_head cfs_symbol_list;
90 cfs_symbol_get(const char *name)
92 struct list_head *walker;
93 struct cfs_symbol *sym = NULL;
95 down_read(&cfs_symbol_lock);
96 list_for_each(walker, &cfs_symbol_list) {
97 sym = list_entry (walker, struct cfs_symbol, sym_list);
98 if (!strcmp(sym->name, name)) {
103 up_read(&cfs_symbol_lock);
110 cfs_symbol_put(const char *name)
112 struct list_head *walker;
113 struct cfs_symbol *sym = NULL;
115 down_read(&cfs_symbol_lock);
116 list_for_each(walker, &cfs_symbol_list) {
117 sym = list_entry (walker, struct cfs_symbol, sym_list);
118 if (!strcmp(sym->name, name)) {
120 LASSERT(sym->ref >= 0);
124 up_read(&cfs_symbol_lock);
125 LASSERT(sym != NULL);
131 cfs_symbol_register(const char *name, const void *value)
133 struct list_head *walker;
134 struct cfs_symbol *sym = NULL;
135 struct cfs_symbol *new = NULL;
137 MALLOC(new, struct cfs_symbol *, sizeof(struct cfs_symbol), M_TEMP, M_WAITOK|M_ZERO);
138 strncpy(new->name, name, CFS_SYMBOL_LEN);
139 new->value = (void *)value;
141 CFS_INIT_LIST_HEAD(&new->sym_list);
143 down_write(&cfs_symbol_lock);
144 list_for_each(walker, &cfs_symbol_list) {
145 sym = list_entry (walker, struct cfs_symbol, sym_list);
146 if (!strcmp(sym->name, name)) {
147 up_write(&cfs_symbol_lock);
149 return KERN_NAME_EXISTS;
153 list_add_tail(&new->sym_list, &cfs_symbol_list);
154 up_write(&cfs_symbol_lock);
160 cfs_symbol_unregister(const char *name)
162 struct list_head *walker;
163 struct list_head *nxt;
164 struct cfs_symbol *sym = NULL;
166 down_write(&cfs_symbol_lock);
167 list_for_each_safe(walker, nxt, &cfs_symbol_list) {
168 sym = list_entry (walker, struct cfs_symbol, sym_list);
169 if (!strcmp(sym->name, name)) {
170 LASSERT(sym->ref == 0);
171 list_del (&sym->sym_list);
176 up_write(&cfs_symbol_lock);
184 CFS_INIT_LIST_HEAD(&cfs_symbol_list);
185 init_rwsem(&cfs_symbol_lock);
191 struct list_head *walker;
192 struct cfs_symbol *sym = NULL;
194 down_write(&cfs_symbol_lock);
195 list_for_each(walker, &cfs_symbol_list) {
196 sym = list_entry (walker, struct cfs_symbol, sym_list);
197 LASSERT(sym->ref == 0);
198 list_del (&sym->sym_list);
201 up_write(&cfs_symbol_lock);
203 fini_rwsem(&cfs_symbol_lock);
207 struct kernel_thread_arg
215 struct kernel_thread_arg cfs_thread_arg;
217 #define THREAD_ARG_FREE 0
218 #define THREAD_ARG_HOLD 1
219 #define THREAD_ARG_RECV 2
221 #define set_targ_stat(a, v) atomic_set(&(a)->inuse, v)
222 #define get_targ_stat(a) atomic_read(&(a)->inuse)
225 * Hold the thread argument and set the status of thread_status
226 * to THREAD_ARG_HOLD, if the thread argument is held by other
227 * threads (It's THREAD_ARG_HOLD already), current-thread has to wait.
229 #define thread_arg_hold(pta, _func, _arg) \
231 spin_lock(&(pta)->lock); \
232 if (get_targ_stat(pta) == THREAD_ARG_FREE) { \
233 set_targ_stat((pta), THREAD_ARG_HOLD); \
234 (pta)->arg = (void *)_arg; \
235 (pta)->func = _func; \
236 spin_unlock(&(pta)->lock); \
239 spin_unlock(&(pta)->lock); \
244 * Release the thread argument if the thread argument has been
245 * received by the child-thread (Status of thread_args is
246 * THREAD_ARG_RECV), otherwise current-thread has to wait.
247 * After release, the thread_args' status will be set to
248 * THREAD_ARG_FREE, and others can re-use the thread_args to
249 * create new kernel_thread.
251 #define thread_arg_release(pta) \
253 spin_lock(&(pta)->lock); \
254 if (get_targ_stat(pta) == THREAD_ARG_RECV) { \
256 (pta)->func = NULL; \
257 set_targ_stat(pta, THREAD_ARG_FREE); \
258 spin_unlock(&(pta)->lock); \
261 spin_unlock(&(pta)->lock); \
266 * Receive thread argument (Used in child thread), set the status
267 * of thread_args to THREAD_ARG_RECV.
269 #define __thread_arg_recv_fin(pta, _func, _arg, fin) \
271 spin_lock(&(pta)->lock); \
272 if (get_targ_stat(pta) == THREAD_ARG_HOLD) { \
274 set_targ_stat(pta, THREAD_ARG_RECV);\
276 _func = (pta)->func; \
277 spin_unlock(&(pta)->lock); \
280 spin_unlock(&(pta)->lock); \
285 * Just set the thread_args' status to THREAD_ARG_RECV
287 #define thread_arg_fin(pta) \
289 spin_lock(&(pta)->lock); \
290 assert( get_targ_stat(pta) == THREAD_ARG_HOLD); \
291 set_targ_stat(pta, THREAD_ARG_RECV); \
292 spin_unlock(&(pta)->lock); \
295 #define thread_arg_recv(pta, f, a) __thread_arg_recv_fin(pta, f, a, 1)
296 #define thread_arg_keep(pta, f, a) __thread_arg_recv_fin(pta, f, a, 0)
299 cfs_thread_agent_init(void)
301 set_targ_stat(&cfs_thread_arg, THREAD_ARG_FREE);
302 spin_lock_init(&cfs_thread_arg.lock);
303 cfs_thread_arg.arg = NULL;
304 cfs_thread_arg.func = NULL;
308 cfs_thread_agent_fini(void)
310 assert(get_targ_stat(&cfs_thread_arg) == THREAD_ARG_FREE);
312 spin_lock_done(&cfs_thread_arg.lock);
317 * All requests to create kernel thread will create a new
318 * thread instance of cfs_thread_agent, one by one.
319 * cfs_thread_agent will call the caller's thread function
320 * with argument supplied by caller.
323 cfs_thread_agent (void)
325 cfs_thread_t func = NULL;
328 thread_arg_recv(&cfs_thread_arg, func, arg);
329 /* printf("entry of thread agent (func: %08lx).\n", (void *)func); */
330 assert(func != NULL);
332 /* printf("thread agent exit. (func: %08lx)\n", (void *)func); */
333 (void) thread_terminate(current_thread());
336 extern thread_t kernel_thread(task_t task, void (*start)(void));
339 cfs_create_thread(cfs_thread_t func, void *arg, unsigned long flag)
344 thread_arg_hold(&cfs_thread_arg, func, arg);
345 th = kernel_thread(kernel_task, cfs_thread_agent);
346 thread_arg_release(&cfs_thread_arg);
347 if (th == THREAD_NULL)
352 void cfs_daemonize(char *str)
354 snprintf(cfs_curproc_comm(), CFS_CURPROC_COMM_MAX, "%s", str);
359 * XXX Liang: kexts cannot access sigmask in Darwin8.
360 * it's almost impossible for us to get/set signal mask
361 * without patching kernel.
362 * Should we provide these functions in xnu?
364 * These signal functions almost do nothing now, we
365 * need to investigate more about signal in Darwin.
368 extern int block_procsigmask(struct proc *p, int bit);
370 cfs_sigset_t cfs_block_allsigs()
372 cfs_sigset_t old = 0;
375 block_procsigmask(current_proc(), -1);
380 cfs_sigset_t cfs_block_sigs(sigset_t bit)
382 cfs_sigset_t old = 0;
385 block_procsigmask(current_proc(), bit);
390 /* Block all signals except for the @sigs. It's only used in
391 * Linux kernel, just a dummy here. */
392 cfs_sigset_t cfs_block_sigsinv(unsigned long sigs)
394 cfs_sigset_t old = 0;
398 void cfs_restore_sigs(cfs_sigset_t old)
402 int cfs_signal_pending(void)
406 extern int thread_issignal(proc_t, thread_t, sigset_t);
407 return thread_issignal(current_proc(), current_thread(), (sigset_t)-1);
409 return SHOULDissignal(current_proc(), current_uthread())
413 void cfs_clear_sigpending(void)
417 clear_procsiglist(current_proc(), -1);
423 #else /* !__DARWIN8__ */
425 void lustre_cone_in(boolean_t *state, funnel_t **cone)
427 *cone = thread_funnel_get();
428 if (*cone == network_flock)
429 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
430 else if (*cone == NULL)
431 *state = thread_funnel_set(kernel_flock, TRUE);
434 void lustre_cone_ex(boolean_t state, funnel_t *cone)
436 if (cone == network_flock)
437 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
438 else if (cone == NULL)
439 (void) thread_funnel_set(kernel_flock, state);
442 void lustre_net_in(boolean_t *state, funnel_t **cone)
444 *cone = thread_funnel_get();
445 if (*cone == kernel_flock)
446 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
447 else if (*cone == NULL)
448 *state = thread_funnel_set(network_flock, TRUE);
451 void lustre_net_ex(boolean_t state, funnel_t *cone)
453 if (cone == kernel_flock)
454 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
455 else if (cone == NULL)
456 (void) thread_funnel_set(network_flock, state);
458 #endif /* !__DARWIN8__ */
460 void cfs_waitq_init(struct cfs_waitq *waitq)
462 ksleep_chan_init(&waitq->wq_ksleep_chan);
465 void cfs_waitlink_init(struct cfs_waitlink *link)
467 ksleep_link_init(&link->wl_ksleep_link);
470 void cfs_waitq_add(struct cfs_waitq *waitq, struct cfs_waitlink *link)
472 link->wl_waitq = waitq;
473 ksleep_add(&waitq->wq_ksleep_chan, &link->wl_ksleep_link);
476 void cfs_waitq_add_exclusive(struct cfs_waitq *waitq,
477 struct cfs_waitlink *link)
479 link->wl_waitq = waitq;
480 link->wl_ksleep_link.flags |= KSLEEP_EXCLUSIVE;
481 ksleep_add(&waitq->wq_ksleep_chan, &link->wl_ksleep_link);
484 void cfs_waitq_del(struct cfs_waitq *waitq,
485 struct cfs_waitlink *link)
487 ksleep_del(&waitq->wq_ksleep_chan, &link->wl_ksleep_link);
490 int cfs_waitq_active(struct cfs_waitq *waitq)
495 void cfs_waitq_signal(struct cfs_waitq *waitq)
498 * XXX nikita: do NOT call libcfs_debug_msg() (CDEBUG/ENTRY/EXIT)
499 * from here: this will lead to infinite recursion.
501 ksleep_wake(&waitq->wq_ksleep_chan);
504 void cfs_waitq_signal_nr(struct cfs_waitq *waitq, int nr)
506 ksleep_wake_nr(&waitq->wq_ksleep_chan, nr);
509 void cfs_waitq_broadcast(struct cfs_waitq *waitq)
511 ksleep_wake_all(&waitq->wq_ksleep_chan);
514 void cfs_waitq_wait(struct cfs_waitlink *link, cfs_task_state_t state)
516 ksleep_wait(&link->wl_waitq->wq_ksleep_chan, state);
519 cfs_duration_t cfs_waitq_timedwait(struct cfs_waitlink *link,
520 cfs_task_state_t state,
521 cfs_duration_t timeout)
523 return ksleep_timedwait(&link->wl_waitq->wq_ksleep_chan,
527 typedef void (*ktimer_func_t)(void *);
528 void cfs_timer_init(cfs_timer_t *t, void (* func)(unsigned long), void *arg)
530 ktimer_init(&t->t, (ktimer_func_t)func, arg);
533 void cfs_timer_done(struct cfs_timer *t)
538 void cfs_timer_arm(struct cfs_timer *t, cfs_time_t deadline)
540 ktimer_arm(&t->t, deadline);
543 void cfs_timer_disarm(struct cfs_timer *t)
545 ktimer_disarm(&t->t);
548 int cfs_timer_is_armed(struct cfs_timer *t)
550 return ktimer_is_armed(&t->t);
553 cfs_time_t cfs_timer_deadline(struct cfs_timer *t)
555 return ktimer_deadline(&t->t);
558 void cfs_enter_debugger(void)
561 extern void Debugger(const char * reason);
564 extern void PE_enter_debugger(char *cause);
565 PE_enter_debugger("CFS");
569 int cfs_online_cpus(void)
576 sysctlbyname("hw.activecpu", &activecpu, &size, NULL, 0);
579 host_basic_info_data_t hinfo;
581 int count = HOST_BASIC_INFO_COUNT;
583 kret = host_info(BSD_HOST, HOST_BASIC_INFO, &hinfo, &count);
584 if (kret == KERN_SUCCESS)
585 return (hinfo.avail_cpus);
597 sysctlbyname("hw.ncpu", &ncpu, &size, NULL, 0);