Whamcloud - gitweb
LU-1146 build: batch update copyright messages
[fs/lustre-release.git] / libcfs / libcfs / darwin / darwin-prim.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
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.
11  *
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).
17  *
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
21  *
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
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
30  * Use is subject to license terms.
31  *
32  * Copyright (c) 2011, Whamcloud, Inc.
33  */
34 /*
35  * This file is part of Lustre, http://www.lustre.org/
36  * Lustre is a trademark of Sun Microsystems, Inc.
37  *
38  * libcfs/libcfs/darwin/darwin-prim.c
39  *
40  * Darwin porting library
41  * Make things easy to port
42  *
43  * Author: Phil Schwan <phil@clusterfs.com>
44  */
45
46 #define DEBUG_SUBSYSTEM S_LNET
47
48 #include <mach/mach_types.h>
49 #include <string.h>
50 #include <sys/file.h>
51 #include <sys/conf.h>
52 #include <sys/uio.h>
53 #include <sys/filedesc.h>
54 #include <sys/namei.h>
55 #include <miscfs/devfs/devfs.h>
56 #include <kern/thread.h>
57
58 #include <libcfs/libcfs.h>
59
60 /*
61  * cfs pseudo device, actually pseudo char device in darwin
62  */
63 #define KLNET_MAJOR  -1
64
65 kern_return_t  cfs_psdev_register(cfs_psdev_t *dev) {
66         dev->index = cdevsw_add(KLNET_MAJOR, dev->devsw);
67         if (dev->index < 0) {
68                 printf("libcfs_init: failed to allocate a major number!\n");
69                 return KERN_FAILURE;
70         }
71         dev->handle = devfs_make_node(makedev (dev->index, 0),
72                                       DEVFS_CHAR, UID_ROOT,
73                                       GID_WHEEL, 0666, (char *)dev->name, 0);
74         return KERN_SUCCESS;
75 }
76
77 kern_return_t  cfs_psdev_deregister(cfs_psdev_t *dev) {
78         devfs_remove(dev->handle);
79         cdevsw_remove(dev->index, dev->devsw);
80         return KERN_SUCCESS;
81 }
82
83 /*
84  * KPortal symbol register / unregister support
85  */
86 struct rw_semaphore             cfs_symbol_lock;
87 struct list_head                cfs_symbol_list;
88
89 void *
90 cfs_symbol_get(const char *name)
91 {
92         struct list_head    *walker;
93         struct cfs_symbol   *sym = NULL;
94
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)) {
99                         sym->ref ++;
100                         break;
101                 }
102         }
103         up_read(&cfs_symbol_lock);
104         if (sym != NULL)
105                 return sym->value;
106         return NULL;
107 }
108
109 kern_return_t
110 cfs_symbol_put(const char *name)
111 {
112         struct list_head    *walker;
113         struct cfs_symbol   *sym = NULL;
114
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)) {
119                         sym->ref --;
120                         LASSERT(sym->ref >= 0);
121                         break;
122                 }
123         }
124         up_read(&cfs_symbol_lock);
125         LASSERT(sym != NULL);
126
127         return 0;
128 }
129
130 kern_return_t
131 cfs_symbol_register(const char *name, const void *value)
132 {
133         struct list_head    *walker;
134         struct cfs_symbol   *sym = NULL;
135         struct cfs_symbol   *new = NULL;
136
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;
140         new->ref = 0;
141         CFS_INIT_LIST_HEAD(&new->sym_list);
142
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);
148                         FREE(new, M_TEMP);
149                         return KERN_NAME_EXISTS;
150                 }
151
152         }
153         list_add_tail(&new->sym_list, &cfs_symbol_list);
154         up_write(&cfs_symbol_lock);
155
156         return KERN_SUCCESS;
157 }
158
159 kern_return_t
160 cfs_symbol_unregister(const char *name)
161 {
162         struct list_head    *walker;
163         struct list_head    *nxt;
164         struct cfs_symbol   *sym = NULL;
165
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);
172                         FREE(sym, M_TEMP);
173                         break;
174                 }
175         }
176         up_write(&cfs_symbol_lock);
177
178         return KERN_SUCCESS;
179 }
180
181 void
182 cfs_symbol_init()
183 {
184         CFS_INIT_LIST_HEAD(&cfs_symbol_list);
185         init_rwsem(&cfs_symbol_lock);
186 }
187
188 void
189 cfs_symbol_fini()
190 {
191         struct list_head    *walker;
192         struct cfs_symbol   *sym = NULL;
193
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);
199                 FREE(sym, M_TEMP);
200         }
201         up_write(&cfs_symbol_lock);
202
203         fini_rwsem(&cfs_symbol_lock);
204         return;
205 }
206
207 struct kernel_thread_arg
208 {
209         spinlock_t      lock;
210         atomic_t        inuse;
211         cfs_thread_t    func;
212         void            *arg;
213 };
214
215 struct kernel_thread_arg cfs_thread_arg;
216
217 #define THREAD_ARG_FREE                 0
218 #define THREAD_ARG_HOLD                 1
219 #define THREAD_ARG_RECV                 2
220
221 #define set_targ_stat(a, v)             atomic_set(&(a)->inuse, v)
222 #define get_targ_stat(a)                atomic_read(&(a)->inuse)
223
224 /*
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.
228  */
229 #define thread_arg_hold(pta, _func, _arg)                       \
230         do {                                                    \
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);              \
237                         break;                                  \
238                 }                                               \
239                 spin_unlock(&(pta)->lock);                      \
240                 cfs_schedule();                                 \
241         } while(1);                                             \
242
243 /*
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.
250  */
251 #define thread_arg_release(pta)                                 \
252         do {                                                    \
253                 spin_lock(&(pta)->lock);                        \
254                 if (get_targ_stat(pta) == THREAD_ARG_RECV) {    \
255                         (pta)->arg = NULL;                      \
256                         (pta)->func = NULL;                     \
257                         set_targ_stat(pta, THREAD_ARG_FREE);    \
258                         spin_unlock(&(pta)->lock);              \
259                         break;                                  \
260                 }                                               \
261                 spin_unlock(&(pta)->lock);                      \
262                 cfs_schedule();                                 \
263         } while(1)
264
265 /*
266  * Receive thread argument (Used in child thread), set the status
267  * of thread_args to THREAD_ARG_RECV.
268  */
269 #define __thread_arg_recv_fin(pta, _func, _arg, fin)            \
270         do {                                                    \
271                 spin_lock(&(pta)->lock);                        \
272                 if (get_targ_stat(pta) == THREAD_ARG_HOLD) {    \
273                         if (fin)                                \
274                             set_targ_stat(pta, THREAD_ARG_RECV);\
275                         _arg = (pta)->arg;                      \
276                         _func = (pta)->func;                    \
277                         spin_unlock(&(pta)->lock);              \
278                         break;                                  \
279                 }                                               \
280                 spin_unlock(&(pta)->lock);                      \
281                 cfs_schedule();                                 \
282         } while (1);                                            \
283
284 /*
285  * Just set the thread_args' status to THREAD_ARG_RECV
286  */
287 #define thread_arg_fin(pta)                                     \
288         do {                                                    \
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);                      \
293         } while(0)
294
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)
297
298 void
299 cfs_thread_agent_init(void)
300 {
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;
305 }
306
307 void
308 cfs_thread_agent_fini(void)
309 {
310         assert(get_targ_stat(&cfs_thread_arg) == THREAD_ARG_FREE);
311
312         spin_lock_done(&cfs_thread_arg.lock);
313 }
314
315 /*
316  *
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.
321  */
322 void
323 cfs_thread_agent (void)
324 {
325         cfs_thread_t           func = NULL;
326         void                   *arg = NULL;
327
328         thread_arg_recv(&cfs_thread_arg, func, arg);
329         /* printf("entry of thread agent (func: %08lx).\n", (void *)func); */
330         assert(func != NULL);
331         func(arg);
332         /* printf("thread agent exit. (func: %08lx)\n", (void *)func); */
333         (void) thread_terminate(current_thread());
334 }
335
336 extern thread_t kernel_thread(task_t task, void (*start)(void));
337
338 int
339 cfs_create_thread(cfs_thread_t  func, void *arg, unsigned long flag)
340 {
341         int ret = 0;
342         thread_t th = NULL;
343
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)
348                 ret = -1;
349         return ret;
350 }
351
352 void cfs_daemonize(char *str)
353 {
354         snprintf(cfs_curproc_comm(), CFS_CURPROC_COMM_MAX, "%s", str);
355         return;
356 }
357
358 /*
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?
363  *
364  * These signal functions almost do nothing now, we 
365  * need to investigate more about signal in Darwin.
366  */
367
368 extern int block_procsigmask(struct proc *p,  int bit);
369
370 cfs_sigset_t cfs_block_allsigs()
371 {
372         cfs_sigset_t    old = 0;
373 #ifdef __DARWIN8__
374 #else
375         block_procsigmask(current_proc(), -1);
376 #endif
377         return old;
378 }
379
380 cfs_sigset_t cfs_block_sigs(sigset_t bit)
381 {
382         cfs_sigset_t    old = 0;
383 #ifdef __DARWIN8__
384 #else
385         block_procsigmask(current_proc(), bit);
386 #endif
387         return old;
388 }
389
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)
393 {
394         cfs_sigset_t old = 0;
395         return old;
396 }
397
398 void cfs_restore_sigs(cfs_sigset_t old)
399 {
400 }
401
402 int cfs_signal_pending(void)
403
404 {
405 #ifdef __DARWIN8__
406         extern int thread_issignal(proc_t, thread_t, sigset_t);
407         return thread_issignal(current_proc(), current_thread(), (sigset_t)-1);
408 #else
409         return SHOULDissignal(current_proc(), current_uthread())
410 #endif
411 }
412
413 void cfs_clear_sigpending(void)
414 {
415 #ifdef __DARWIN8__
416 #else
417         clear_procsiglist(current_proc(), -1);
418 #endif
419 }
420
421 #ifdef __DARWIN8__
422
423 #else /* !__DARWIN8__ */
424
425 void lustre_cone_in(boolean_t *state, funnel_t **cone)
426 {
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);
432 }
433
434 void lustre_cone_ex(boolean_t state, funnel_t *cone)
435 {
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);
440 }
441
442 void lustre_net_in(boolean_t *state, funnel_t **cone)
443 {
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);
449 }
450
451 void lustre_net_ex(boolean_t state, funnel_t *cone)
452 {
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);
457 }
458 #endif /* !__DARWIN8__ */
459
460 void cfs_waitq_init(struct cfs_waitq *waitq)
461 {
462         ksleep_chan_init(&waitq->wq_ksleep_chan);
463 }
464
465 void cfs_waitlink_init(struct cfs_waitlink *link)
466 {
467         ksleep_link_init(&link->wl_ksleep_link);
468 }
469
470 void cfs_waitq_add(struct cfs_waitq *waitq, struct cfs_waitlink *link)
471 {
472         link->wl_waitq = waitq;
473         ksleep_add(&waitq->wq_ksleep_chan, &link->wl_ksleep_link);
474 }
475
476 void cfs_waitq_add_exclusive(struct cfs_waitq *waitq,
477                              struct cfs_waitlink *link)
478 {
479         link->wl_waitq = waitq;
480         link->wl_ksleep_link.flags |= KSLEEP_EXCLUSIVE;
481         ksleep_add(&waitq->wq_ksleep_chan, &link->wl_ksleep_link);
482 }
483
484 void cfs_waitq_del(struct cfs_waitq *waitq,
485                    struct cfs_waitlink *link)
486 {
487         ksleep_del(&waitq->wq_ksleep_chan, &link->wl_ksleep_link);
488 }
489
490 int cfs_waitq_active(struct cfs_waitq *waitq)
491 {
492         return (1);
493 }
494
495 void cfs_waitq_signal(struct cfs_waitq *waitq)
496 {
497         /*
498          * XXX nikita: do NOT call libcfs_debug_msg() (CDEBUG/ENTRY/EXIT)
499          * from here: this will lead to infinite recursion.
500          */
501         ksleep_wake(&waitq->wq_ksleep_chan);
502 }
503
504 void cfs_waitq_signal_nr(struct cfs_waitq *waitq, int nr)
505 {
506         ksleep_wake_nr(&waitq->wq_ksleep_chan, nr);
507 }
508
509 void cfs_waitq_broadcast(struct cfs_waitq *waitq)
510 {
511         ksleep_wake_all(&waitq->wq_ksleep_chan);
512 }
513
514 void cfs_waitq_wait(struct cfs_waitlink *link, cfs_task_state_t state)
515 {
516         ksleep_wait(&link->wl_waitq->wq_ksleep_chan, state);
517 }
518
519 cfs_duration_t  cfs_waitq_timedwait(struct cfs_waitlink *link,
520                                     cfs_task_state_t state,
521                                     cfs_duration_t timeout)
522 {
523         return ksleep_timedwait(&link->wl_waitq->wq_ksleep_chan, 
524                                 state, timeout);
525 }
526
527 typedef  void (*ktimer_func_t)(void *);
528 void cfs_timer_init(cfs_timer_t *t, void (* func)(unsigned long), void *arg)
529 {
530         ktimer_init(&t->t, (ktimer_func_t)func, arg);
531 }
532
533 void cfs_timer_done(struct cfs_timer *t)
534 {
535         ktimer_done(&t->t);
536 }
537
538 void cfs_timer_arm(struct cfs_timer *t, cfs_time_t deadline)
539 {
540         ktimer_arm(&t->t, deadline);
541 }
542
543 void cfs_timer_disarm(struct cfs_timer *t)
544 {
545         ktimer_disarm(&t->t);
546 }
547
548 int  cfs_timer_is_armed(struct cfs_timer *t)
549 {
550         return ktimer_is_armed(&t->t);
551 }
552
553 cfs_time_t cfs_timer_deadline(struct cfs_timer *t)
554 {
555         return ktimer_deadline(&t->t);
556 }
557
558 void cfs_enter_debugger(void)
559 {
560 #ifdef __DARWIN8__
561         extern void Debugger(const char * reason);
562         Debugger("CFS");
563 #else
564         extern void PE_enter_debugger(char *cause);
565         PE_enter_debugger("CFS");
566 #endif
567 }
568
569 int cfs_online_cpus(void)
570 {
571         int     activecpu;
572         size_t  size;
573
574 #ifdef __DARWIN8__ 
575         size = sizeof(int);
576         sysctlbyname("hw.activecpu", &activecpu, &size, NULL, 0);
577         return activecpu;
578 #else
579         host_basic_info_data_t hinfo;
580         kern_return_t kret;
581         int count = HOST_BASIC_INFO_COUNT;
582 #define BSD_HOST 1
583         kret = host_info(BSD_HOST, HOST_BASIC_INFO, &hinfo, &count);
584         if (kret == KERN_SUCCESS) 
585                 return (hinfo.avail_cpus);
586         return(-EINVAL);
587 #endif
588 }
589
590 int cfs_ncpus(void)
591 {
592         int     ncpu;
593         size_t  size;
594
595         size = sizeof(int);
596
597         sysctlbyname("hw.ncpu", &ncpu, &size, NULL, 0);
598         return ncpu;
599 }