Whamcloud - gitweb
LU-3963 libcfs: cleanup list operations
[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  misc_register(struct miscdevice *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  misc_deregister(struct miscdevice *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         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         list_add_tail(&new->sym_list, &cfs_symbol_list);
151         up_write(&cfs_symbol_lock);
152         return KERN_SUCCESS;
153 }
154
155 kern_return_t
156 cfs_symbol_unregister(const char *name)
157 {
158         struct list_head  *walker;
159         struct list_head  *nxt;
160         struct cfs_symbol *sym = NULL;
161
162         down_write(&cfs_symbol_lock);
163         list_for_each_safe(walker, nxt, &cfs_symbol_list) {
164                 sym = list_entry(walker, struct cfs_symbol, sym_list);
165                 if (!strcmp(sym->name, name)) {
166                         LASSERT(sym->ref == 0);
167                         list_del(&sym->sym_list);
168                         FREE(sym, M_TEMP);
169                         break;
170                 }
171         }
172         up_write(&cfs_symbol_lock);
173
174         return KERN_SUCCESS;
175 }
176
177 void
178 cfs_symbol_init()
179 {
180         INIT_LIST_HEAD(&cfs_symbol_list);
181         init_rwsem(&cfs_symbol_lock);
182 }
183
184 void
185 cfs_symbol_fini()
186 {
187         struct list_head  *walker;
188         struct cfs_symbol *sym = NULL;
189
190         down_write(&cfs_symbol_lock);
191         list_for_each(walker, &cfs_symbol_list) {
192                 sym = list_entry(walker, struct cfs_symbol, sym_list);
193                 LASSERT(sym->ref == 0);
194                 list_del(&sym->sym_list);
195                 FREE(sym, M_TEMP);
196         }
197         up_write(&cfs_symbol_lock);
198
199         fini_rwsem(&cfs_symbol_lock);
200         return;
201 }
202
203 struct kernel_thread_arg
204 {
205         spinlock_t      lock;
206         atomic_t        inuse;
207         cfs_thread_t    func;
208         void            *arg;
209 };
210
211 struct kernel_thread_arg cfs_thread_arg;
212
213 #define THREAD_ARG_FREE                 0
214 #define THREAD_ARG_HOLD                 1
215 #define THREAD_ARG_RECV                 2
216
217 #define set_targ_stat(a, v)             atomic_set(&(a)->inuse, v)
218 #define get_targ_stat(a)                atomic_read(&(a)->inuse)
219
220 /*
221  * Hold the thread argument and set the status of thread_status
222  * to THREAD_ARG_HOLD, if the thread argument is held by other
223  * threads (It's THREAD_ARG_HOLD already), current-thread has to wait.
224  */
225 #define thread_arg_hold(pta, _func, _arg)                       \
226         do {                                                    \
227                 spin_lock(&(pta)->lock);                        \
228                 if (get_targ_stat(pta) == THREAD_ARG_FREE) {    \
229                         set_targ_stat((pta), THREAD_ARG_HOLD);  \
230                         (pta)->arg = (void *)_arg;              \
231                         (pta)->func = _func;                    \
232                         spin_unlock(&(pta)->lock);              \
233                         break;                                  \
234                 }                                               \
235                 spin_unlock(&(pta)->lock);                      \
236                 schedule();                                     \
237         } while(1);                                             \
238
239 /*
240  * Release the thread argument if the thread argument has been
241  * received by the child-thread (Status of thread_args is
242  * THREAD_ARG_RECV), otherwise current-thread has to wait.
243  * After release, the thread_args' status will be set to
244  * THREAD_ARG_FREE, and others can re-use the thread_args to
245  * create new kernel_thread.
246  */
247 #define thread_arg_release(pta)                                 \
248         do {                                                    \
249                 spin_lock(&(pta)->lock);                        \
250                 if (get_targ_stat(pta) == THREAD_ARG_RECV) {    \
251                         (pta)->arg = NULL;                      \
252                         (pta)->func = NULL;                     \
253                         set_targ_stat(pta, THREAD_ARG_FREE);    \
254                         spin_unlock(&(pta)->lock);              \
255                         break;                                  \
256                 }                                               \
257                 spin_unlock(&(pta)->lock);                      \
258                 schedule();                                     \
259         } while(1)
260
261 /*
262  * Receive thread argument (Used in child thread), set the status
263  * of thread_args to THREAD_ARG_RECV.
264  */
265 #define __thread_arg_recv_fin(pta, _func, _arg, fin)            \
266         do {                                                    \
267                 spin_lock(&(pta)->lock);                        \
268                 if (get_targ_stat(pta) == THREAD_ARG_HOLD) {    \
269                         if (fin)                                \
270                             set_targ_stat(pta, THREAD_ARG_RECV);\
271                         _arg = (pta)->arg;                      \
272                         _func = (pta)->func;                    \
273                         spin_unlock(&(pta)->lock);              \
274                         break;                                  \
275                 }                                               \
276                 spin_unlock(&(pta)->lock);                      \
277                 schedule();                                     \
278         } while (1);                                            \
279
280 /*
281  * Just set the thread_args' status to THREAD_ARG_RECV
282  */
283 #define thread_arg_fin(pta)                                     \
284         do {                                                    \
285                 spin_lock(&(pta)->lock);                        \
286                 assert( get_targ_stat(pta) == THREAD_ARG_HOLD); \
287                 set_targ_stat(pta, THREAD_ARG_RECV);            \
288                 spin_unlock(&(pta)->lock);                      \
289         } while(0)
290
291 #define thread_arg_recv(pta, f, a)      __thread_arg_recv_fin(pta, f, a, 1)
292 #define thread_arg_keep(pta, f, a)      __thread_arg_recv_fin(pta, f, a, 0)
293
294 void
295 cfs_thread_agent_init(void)
296 {
297         set_targ_stat(&cfs_thread_arg, THREAD_ARG_FREE);
298         spin_lock_init(&cfs_thread_arg.lock);
299         cfs_thread_arg.arg = NULL;
300         cfs_thread_arg.func = NULL;
301 }
302
303 void
304 cfs_thread_agent_fini(void)
305 {
306         assert(get_targ_stat(&cfs_thread_arg) == THREAD_ARG_FREE);
307
308         spin_lock_done(&cfs_thread_arg.lock);
309 }
310
311 /*
312  *
313  * All requests to create kernel thread will create a new
314  * thread instance of cfs_thread_agent, one by one.
315  * cfs_thread_agent will call the caller's thread function
316  * with argument supplied by caller.
317  */
318 void
319 cfs_thread_agent (void)
320 {
321         cfs_thread_t           func = NULL;
322         void                   *arg = NULL;
323
324         thread_arg_recv(&cfs_thread_arg, func, arg);
325         /* printf("entry of thread agent (func: %08lx).\n", (void *)func); */
326         assert(func != NULL);
327         func(arg);
328         /* printf("thread agent exit. (func: %08lx)\n", (void *)func); */
329         (void) thread_terminate(current_thread());
330 }
331
332 extern thread_t kernel_thread(task_t task, void (*start)(void));
333
334 struct task_struct
335 kthread_run(cfs_thread_t func, void *arg, const char namefmt[], ...)
336 {
337         int ret = 0;
338         thread_t th = NULL;
339
340         thread_arg_hold(&cfs_thread_arg, func, arg);
341         th = kernel_thread(kernel_task, cfs_thread_agent);
342         thread_arg_release(&cfs_thread_arg);
343         if (th != THREAD_NULL) {
344                 /*
345                  * FIXME: change child thread name...
346                  * current_comm() is already broken. So it is left as is...
347                 va_list args;
348                 va_start(args, namefmt);
349                 snprintf(current_comm(), CFS_CURPROC_COMM_MAX,
350                          namefmt, args);
351                 va_end(args);
352                  */
353         } else {
354                 ret = -1;
355         }
356         return (struct task_struct)((long)ret);
357 }
358
359 /*
360  * XXX Liang: kexts cannot access sigmask in Darwin8.
361  * it's almost impossible for us to get/set signal mask
362  * without patching kernel.
363  * Should we provide these functions in xnu?
364  *
365  * These signal functions almost do nothing now, we
366  * need to investigate more about signal in Darwin.
367  */
368
369 extern int block_procsigmask(struct proc *p,  int bit);
370
371 sigset_t cfs_block_allsigs()
372 {
373         sigset_t    old = 0;
374 #ifdef __DARWIN8__
375 #else
376         block_procsigmask(current_proc(), -1);
377 #endif
378         return old;
379 }
380
381 sigset_t cfs_block_sigs(unsigned long sigs)
382 {
383         sigset_t    old = 0;
384 #ifdef __DARWIN8__
385 #else
386         block_procsigmask(current_proc(), sigs);
387 #endif
388         return old;
389 }
390
391 /* Block all signals except for the @sigs. It's only used in
392  * Linux kernel, just a dummy here. */
393 sigset_t cfs_block_sigsinv(unsigned long sigs)
394 {
395         sigset_t old = 0;
396         return old;
397 }
398
399 void cfs_restore_sigs(sigset_t old)
400 {
401 }
402
403 int cfs_signal_pending(void)
404
405 {
406 #ifdef __DARWIN8__
407         extern int thread_issignal(proc_t, thread_t, sigset_t);
408         return thread_issignal(current_proc(), current_thread(), (sigset_t)-1);
409 #else
410         return SHOULDissignal(current_proc(), current_uthread())
411 #endif
412 }
413
414 void cfs_clear_sigpending(void)
415 {
416 #ifdef __DARWIN8__
417 #else
418         clear_procsiglist(current_proc(), -1);
419 #endif
420 }
421
422 #ifdef __DARWIN8__
423
424 #else /* !__DARWIN8__ */
425
426 void lustre_cone_in(boolean_t *state, funnel_t **cone)
427 {
428         *cone = thread_funnel_get();
429         if (*cone == network_flock)
430                 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
431         else if (*cone == NULL)
432                 *state = thread_funnel_set(kernel_flock, TRUE);
433 }
434
435 void lustre_cone_ex(boolean_t state, funnel_t *cone)
436 {
437         if (cone == network_flock)
438                 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
439         else if (cone == NULL)
440                 (void) thread_funnel_set(kernel_flock, state);
441 }
442
443 void lustre_net_in(boolean_t *state, funnel_t **cone)
444 {
445         *cone = thread_funnel_get();
446         if (*cone == kernel_flock)
447                 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
448         else if (*cone == NULL)
449                 *state = thread_funnel_set(network_flock, TRUE);
450 }
451
452 void lustre_net_ex(boolean_t state, funnel_t *cone)
453 {
454         if (cone == kernel_flock)
455                 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
456         else if (cone == NULL)
457                 (void) thread_funnel_set(network_flock, state);
458 }
459 #endif /* !__DARWIN8__ */
460
461 void init_waitqueue_head(struct cfs_waitq *waitq)
462 {
463         ksleep_chan_init(&waitq->wq_ksleep_chan);
464 }
465
466 void init_waitqueue_entry_current(struct cfs_waitlink *link)
467 {
468         ksleep_link_init(&link->wl_ksleep_link);
469 }
470
471 void add_wait_queue(struct cfs_waitq *waitq, struct cfs_waitlink *link)
472 {
473         link->wl_waitq = waitq;
474         ksleep_add(&waitq->wq_ksleep_chan, &link->wl_ksleep_link);
475 }
476
477 void add_wait_queue_exclusive(struct cfs_waitq *waitq,
478                               struct cfs_waitlink *link)
479 {
480         link->wl_waitq = waitq;
481         link->wl_ksleep_link.flags |= KSLEEP_EXCLUSIVE;
482         ksleep_add(&waitq->wq_ksleep_chan, &link->wl_ksleep_link);
483 }
484
485 void remove_wait_queue(struct cfs_waitq *waitq,
486                    struct cfs_waitlink *link)
487 {
488         ksleep_del(&waitq->wq_ksleep_chan, &link->wl_ksleep_link);
489 }
490
491 int waitqueue_active(struct cfs_waitq *waitq)
492 {
493         return (1);
494 }
495
496 void wake_up(struct cfs_waitq *waitq)
497 {
498         /*
499          * XXX nikita: do NOT call libcfs_debug_msg() (CDEBUG/ENTRY/EXIT)
500          * from here: this will lead to infinite recursion.
501          */
502         ksleep_wake(&waitq->wq_ksleep_chan);
503 }
504
505 void wake_up_nr(struct cfs_waitq *waitq, int nr)
506 {
507         ksleep_wake_nr(&waitq->wq_ksleep_chan, nr);
508 }
509
510 void wake_up_all(struct cfs_waitq *waitq)
511 {
512         ksleep_wake_all(&waitq->wq_ksleep_chan);
513 }
514
515 void waitq_wait(struct cfs_waitlink *link, long state)
516 {
517         ksleep_wait(&link->wl_waitq->wq_ksleep_chan, state);
518 }
519
520 cfs_duration_t  waitq_timedwait(struct cfs_waitlink *link,
521                                     long state,
522                                     cfs_duration_t timeout)
523 {
524         return ksleep_timedwait(&link->wl_waitq->wq_ksleep_chan,
525                                 state, timeout);
526 }
527
528 typedef  void (*ktimer_func_t)(void *);
529 void cfs_timer_init(struct timer_list *t, void (* func)(unsigned long), void *arg)
530 {
531         ktimer_init(&t->t, (ktimer_func_t)func, arg);
532 }
533
534 void cfs_timer_done(struct cfs_timer *t)
535 {
536         ktimer_done(&t->t);
537 }
538
539 void cfs_timer_arm(struct cfs_timer *t, cfs_time_t deadline)
540 {
541         ktimer_arm(&t->t, deadline);
542 }
543
544 void cfs_timer_disarm(struct cfs_timer *t)
545 {
546         ktimer_disarm(&t->t);
547 }
548
549 int  cfs_timer_is_armed(struct cfs_timer *t)
550 {
551         return ktimer_is_armed(&t->t);
552 }
553
554 cfs_time_t cfs_timer_deadline(struct cfs_timer *t)
555 {
556         return ktimer_deadline(&t->t);
557 }
558
559 void cfs_enter_debugger(void)
560 {
561 #ifdef __DARWIN8__
562         extern void Debugger(const char * reason);
563         Debugger("CFS");
564 #else
565         extern void PE_enter_debugger(char *cause);
566         PE_enter_debugger("CFS");
567 #endif
568 }
569
570 int cfs_online_cpus(void)
571 {
572         int     activecpu;
573         size_t  size;
574
575 #ifdef __DARWIN8__
576         size = sizeof(int);
577         sysctlbyname("hw.activecpu", &activecpu, &size, NULL, 0);
578         return activecpu;
579 #else
580         host_basic_info_data_t hinfo;
581         kern_return_t kret;
582         int count = HOST_BASIC_INFO_COUNT;
583 #define BSD_HOST 1
584         kret = host_info(BSD_HOST, HOST_BASIC_INFO, &hinfo, &count);
585         if (kret == KERN_SUCCESS)
586                 return (hinfo.avail_cpus);
587         return(-EINVAL);
588 #endif
589 }
590
591 int cfs_ncpus(void)
592 {
593         int     ncpu;
594         size_t  size;
595
596         size = sizeof(int);
597
598         sysctlbyname("hw.ncpu", &ncpu, &size, NULL, 0);
599         return ncpu;
600 }