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