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