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