Whamcloud - gitweb
LU-1346 libcfs: cleanup waitq related primitives
[fs/lustre-release.git] / libcfs / include / libcfs / darwin / darwin-prim.h
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 /*
31  * This file is part of Lustre, http://www.lustre.org/
32  * Lustre is a trademark of Sun Microsystems, Inc.
33  */
34
35 #ifndef __LIBCFS_DARWIN_CFS_PRIM_H__
36 #define __LIBCFS_DARWIN_CFS_PRIM_H__
37
38 #ifndef __LIBCFS_LIBCFS_H__
39 #error Do not #include this file directly. #include <libcfs/libcfs.h> instead
40 #endif
41
42 #ifndef EXPORT_SYMBOL
43 # define EXPORT_SYMBOL(s)
44 #endif
45
46 #ifdef __KERNEL__
47 #include <sys/types.h>
48 #include <sys/systm.h>
49
50 #ifndef __DARWIN8__
51 # ifndef __APPLE_API_PRIVATE
52 #  define __APPLE_API_PRIVATE
53 #  include <sys/user.h>
54 #  undef __APPLE_API_PRIVATE
55 # else
56 #  include <sys/user.h>
57 # endif
58 # include <mach/mach_traps.h>
59 # include <mach/thread_switch.h>
60 # include <machine/cpu_number.h>
61 #endif /* !__DARWIN8__ */
62
63 #include <sys/kernel.h>
64
65 #include <mach/thread_act.h>
66 #include <mach/mach_types.h>
67 #include <mach/time_value.h>
68 #include <kern/sched_prim.h>
69 #include <vm/pmap.h>
70 #include <vm/vm_kern.h>
71 #include <mach/machine/vm_param.h>
72 #include <machine/machine_routines.h>
73 #include <kern/clock.h>
74 #include <kern/thread_call.h>
75 #include <sys/param.h>
76 #include <sys/vm.h>
77
78 #include <libcfs/darwin/darwin-types.h>
79 #include <libcfs/darwin/darwin-utils.h>
80 #include <libcfs/darwin/darwin-lock.h>
81
82 /*
83  * Symbol functions for libcfs
84  *
85  * OSX has no facility for use to register symbol.
86  * So we have to implement it.
87  */
88 #define CFS_SYMBOL_LEN     64
89
90 struct  cfs_symbol {
91         char    name[CFS_SYMBOL_LEN];
92         void    *value;
93         int     ref;
94         struct  list_head sym_list;
95 };
96
97 extern kern_return_t            cfs_symbol_register(const char *, const void *);
98 extern kern_return_t            cfs_symbol_unregister(const char *);
99 extern void *                   cfs_symbol_get(const char *);
100 extern kern_return_t            cfs_symbol_put(const char *);
101
102 /*
103  * sysctl typedef
104  *
105  * User can register/unregister a list of sysctl_oids
106  * sysctl_oid is data struct of osx's sysctl-entry
107  */
108 #define         CONFIG_SYSCTL   1
109
110 #define ctl_table sysctl_oid
111 struct ctl_table *register_sysctl_table(struct ctl_table *table);
112 void unregister_sysctl_table(struct ctl_table *table);
113
114 /*
115  * Proc file system APIs, no /proc fs support in OSX
116  */
117 typedef struct cfs_proc_dir_entry {
118         void            *data;
119 } cfs_proc_dir_entry_t;
120
121 cfs_proc_dir_entry_t * cfs_create_proc_entry(char *name, int mod,
122                                           cfs_proc_dir_entry_t *parent);
123 void cfs_free_proc_entry(cfs_proc_dir_entry_t *de);
124 void cfs_remove_proc_entry(char *name, cfs_proc_dir_entry_t *entry);
125
126 typedef int (cfs_read_proc_t)(char *page, char **start, off_t off,
127                           int count, int *eof, void *data);
128 typedef int (cfs_write_proc_t)(struct file *file, const char *buffer,
129                            unsigned long count, void *data);
130
131 /*
132  * cfs pseudo device
133  *
134  * struct miscdevice
135  * misc_register:
136  * misc_deregister:
137  */
138 struct miscdevice{
139         int             index;
140         void            *handle;
141         const char      *name;
142         struct cdevsw   *devsw;
143         void            *private;
144 };
145
146 extern kern_return_t            misc_register(struct miscdevice *);
147 extern kern_return_t            misc_deregister(struct miscdevice *);
148
149 /*
150  * Task struct and ...
151  *
152  * Using BSD current_proc in Darwin
153  */
154 extern boolean_t        assert_wait_possible(void);
155 extern void             *get_bsdtask_info(task_t);
156
157 #ifdef __DARWIN8__
158
159 typedef struct {}               cfs_task_t;
160 #define cfs_current()           ((cfs_task_t *)current_thread())
161 #else   /* !__DARWIN8__ */
162
163 typedef struct uthread          cfs_task_t;
164
165 #define current_uthread()       ((struct uthread *)get_bsdthread_info(current_act()))
166 #define cfs_current()           current_uthread()
167
168 #endif /* !__DARWIN8__ */
169
170 #define cfs_task_lock(t)        do {;} while (0)
171 #define cfs_task_unlock(t)      do {;} while (0)
172
173 #define set_current_state(s)    do {;} while (0)
174
175 #define CFS_DECL_JOURNAL_DATA   
176 #define CFS_PUSH_JOURNAL        do {;} while(0)
177 #define CFS_POP_JOURNAL         do {;} while(0)
178
179 /*
180  * Kernel thread:
181  *
182  * OSX kernel thread can not be created with args,
183  * so we have to implement new APIs to create thread with args
184  */
185
186 typedef int (*cfs_thread_t)(void *);
187
188 extern task_t   kernel_task;
189
190 /*
191  * cloning flags, no use in OSX, just copy them from Linux
192  */
193 #define CSIGNAL         0x000000ff      /* signal mask to be sent at exit */
194 #define CLONE_VM        0x00000100      /* set if VM shared between processes */
195 #define CLONE_FS        0x00000200      /* set if fs info shared between processes */
196 #define CLONE_FILES     0x00000400      /* set if open files shared between processes */
197 #define CLONE_SIGHAND   0x00000800      /* set if signal handlers and blocked signals shared */
198 #define CLONE_PID       0x00001000      /* set if pid shared */
199 #define CLONE_PTRACE    0x00002000      /* set if we want to let tracing continue on the child too */
200 #define CLONE_VFORK     0x00004000      /* set if the parent wants the child to wake it up on mm_release */
201 #define CLONE_PARENT    0x00008000      /* set if we want to have the same parent as the cloner */
202 #define CLONE_THREAD    0x00010000      /* Same thread group? */
203 #define CLONE_NEWNS     0x00020000      /* New namespace group? */
204
205 #define CLONE_SIGNAL    (CLONE_SIGHAND | CLONE_THREAD)
206
207 extern cfs_task_t kthread_run(cfs_thread_t func, void *arg,
208                               const char namefmt[], ...);
209
210 /*
211  * Wait Queue implementation
212  *
213  * Like wait_queue in Linux
214  */
215 typedef struct cfs_waitq {
216         struct ksleep_chan wq_ksleep_chan;
217 } wait_queue_head_t;
218
219 typedef struct cfs_waitlink {
220         struct cfs_waitq   *wl_waitq;
221         struct ksleep_link  wl_ksleep_link;
222 } wait_queue_t;
223
224 #define TASK_INTERRUPTIBLE      THREAD_ABORTSAFE
225 #define TASK_UNINTERRUPTIBLE            THREAD_UNINT
226
227 void init_waitqueue_head(struct cfs_waitq *waitq);
228 void init_waitqueue_entry_current(struct cfs_waitlink *link);
229
230 void add_wait_queue(struct cfs_waitq *waitq, struct cfs_waitlink *link);
231 void add_wait_queue_exclusive(struct cfs_waitq *waitq,
232                              struct cfs_waitlink *link);
233 void remove_wait_queue(struct cfs_waitq *waitq, struct cfs_waitlink *link);
234 int  waitqueue_active(struct cfs_waitq *waitq);
235
236 void wake_up(struct cfs_waitq *waitq);
237 void wake_up_nr(struct cfs_waitq *waitq, int nr);
238 void wake_up_all(struct cfs_waitq *waitq);
239
240 void waitq_wait(struct cfs_waitlink *link, long state);
241 cfs_duration_t waitq_timedwait(struct cfs_waitlink *link,
242                                    long state,
243                                    cfs_duration_t timeout);
244
245 /*
246  * Thread schedule APIs.
247  */
248 #define MAX_SCHEDULE_TIMEOUT    ((long)(~0UL>>12))
249 extern void thread_set_timer_deadline(__u64 deadline);
250 extern void thread_cancel_timer(void);
251
252 static inline int schedule_timeout(int state, int64_t timeout)
253 {
254         int          result;
255         
256 #ifdef __DARWIN8__
257         result = assert_wait((event_t)current_thread(), state);
258 #else
259         result = assert_wait((event_t)current_uthread(), state);
260 #endif
261         if (timeout > 0) {
262                 __u64 expire;
263                 nanoseconds_to_absolutetime(timeout, &expire);
264                 clock_absolutetime_interval_to_deadline(expire, &expire);
265                 thread_set_timer_deadline(expire);
266         }
267         if (result == THREAD_WAITING)
268                 result = thread_block(THREAD_CONTINUE_NULL);
269         if (timeout > 0)
270                 thread_cancel_timer();
271         if (result == THREAD_TIMED_OUT)
272                 result = 0;
273         else
274                 result = 1;
275         return result;
276 }
277
278 #define schedule()      schedule_timeout(TASK_UNINTERRUPTIBLE, CFS_TICK)
279 #define cfs_pause(tick) schedule_timeout(TASK_UNINTERRUPTIBLE, tick)
280
281 #define __wait_event(wq, condition)                             \
282 do {                                                            \
283         struct cfs_waitlink __wait;                             \
284                                                                 \
285         init_waitqueue_entry_current(&__wait);                  \
286         for (;;) {                                              \
287                 add_wait_queue(&wq, &__wait);                   \
288                 if (condition)                                  \
289                         break;                                  \
290                 waitq_wait(&__wait, TASK_UNINTERRUPTIBLE);      \
291                 remove_wait_queue(&wq, &__wait);                \
292         }                                                       \
293         remove_wait_queue(&wq, &__wait);                        \
294 } while (0)
295
296 #define wait_event(wq, condition)                               \
297 do {                                                            \
298         if (condition)                                          \
299                 break;                                          \
300         __wait_event(wq, condition);                            \
301 } while (0)
302
303 #define __wait_event_interruptible(wq, condition, ex, ret)      \
304 do {                                                            \
305         struct cfs_waitlink __wait;                             \
306                                                                 \
307         init_waitqueue_entry_current(&__wait);                  \
308         for (;;) {                                              \
309                 if (ex == 0)                                    \
310                         add_wait_queue(&wq, &__wait);           \
311                 else                                            \
312                         add_wait_queue_exclusive(&wq, &__wait); \
313                 if (condition)                                  \
314                         break;                                  \
315                 if (!cfs_signal_pending()) {                    \
316                         waitq_wait(&__wait,                     \
317                                        TASK_INTERRUPTIBLE);     \
318                         remove_wait_queue(&wq, &__wait);        \
319                         continue;                               \
320                 }                                               \
321                 ret = -ERESTARTSYS;                             \
322                 break;                                          \
323         }                                                       \
324         remove_wait_queue(&wq, &__wait);                        \
325 } while (0)
326
327 #define wait_event_interruptible(wq, condition)                 \
328 ({                                                              \
329         int __ret = 0;                                          \
330         if (!condition)                                         \
331                 __wait_event_interruptible(wq, condition,       \
332                                            0, __ret);           \
333         __ret;                                                  \
334 })
335
336 #define wait_event_interruptible_exclusive(wq, condition)       \
337 ({                                                              \
338         int __ret = 0;                                          \
339         if (!condition)                                         \
340                 __wait_event_interruptible(wq, condition,       \
341                                            1, __ret);           \
342         __ret;                                                  \
343 })
344
345 #ifndef __DARWIN8__
346 extern void     wakeup_one __P((void * chan));
347 #endif
348 /* only used in tests */
349 #define wake_up_process(p)                                      \
350         do {                                                    \
351                 wakeup_one((caddr_t)p);                         \
352         } while (0)
353         
354 /* used in couple of places */
355 static inline void sleep_on(wait_queue_head_t *waitq)
356 {
357         wait_queue_t link;
358         
359         init_waitqueue_entry_current(&link);
360         add_wait_queue(waitq, &link);
361         waitq_wait(&link, TASK_UNINTERRUPTIBLE);
362         remove_wait_queue(waitq, &link);
363 }
364
365 /*
366  * Signal
367  */
368 typedef sigset_t        cfs_sigset_t;
369
370 /*
371  * Timer
372  */
373 typedef struct cfs_timer {
374         struct ktimer t;
375 } cfs_timer_t;
376
377 #define cfs_init_timer(t)       do {} while(0)
378 void cfs_timer_init(struct cfs_timer *t, void (*func)(unsigned long), void *arg);
379 void cfs_timer_done(struct cfs_timer *t);
380 void cfs_timer_arm(struct cfs_timer *t, cfs_time_t deadline);
381 void cfs_timer_disarm(struct cfs_timer *t);
382 int  cfs_timer_is_armed(struct cfs_timer *t);
383
384 cfs_time_t cfs_timer_deadline(struct cfs_timer *t);
385
386 /*
387  * Ioctl
388  * We don't need to copy out everything in osx
389  */
390 #define cfs_ioctl_data_out(a, d, l)                     \
391         ({                                              \
392                 int __size;                             \
393                 int __rc = 0;                           \
394                 assert((l) >= sizeof(*d));              \
395                 __size = (l) - sizeof(*d);              \
396                 if (__size > 0)                         \
397                         __rc = copy_to_user((void *)a + __size, \
398                              (void *)d + __size,        \
399                              __size);                   \
400                 __rc;                                   \
401         })
402
403 /*
404  * CPU
405  */
406 /* Run in PowerG5 who is PPC64 */
407 #define SMP_CACHE_BYTES                         128
408 #define __cacheline_aligned                     __attribute__((__aligned__(SMP_CACHE_BYTES)))
409 #define NR_CPUS                                 2
410
411 /* 
412  * XXX Liang: patch xnu and export current_processor()?
413  *
414  * #define smp_processor_id()                   current_processor()
415  */
416 #define smp_processor_id()                      0
417 /* XXX smp_call_function is not supported in xnu */
418 #define smp_call_function(f, a, n, w)           do {} while(0)
419 int cfs_online_cpus(void);
420
421 /*
422  * Misc
423  */
424 extern int is_suser(void);
425
426 #ifndef likely
427 #define likely(exp) (exp)
428 #endif
429 #ifndef unlikely
430 #define unlikely(exp) (exp)
431 #endif
432
433 #define lock_kernel()                                   do {} while(0)
434 #define unlock_kernel()                                 do {} while(0)
435
436 #define call_usermodehelper(path, argv, envp, 1)        (0)
437
438 #define cfs_module(name, version, init, fini)                           \
439 extern kern_return_t _start(kmod_info_t *ki, void *data);               \
440 extern kern_return_t _stop(kmod_info_t *ki, void *data);                \
441 __private_extern__ kern_return_t name##_start(kmod_info_t *ki, void *data); \
442 __private_extern__ kern_return_t name##_stop(kmod_info_t *ki, void *data); \
443                                                                         \
444 kmod_info_t KMOD_INFO_NAME = { 0, KMOD_INFO_VERSION, -1,                \
445                                { "com.clusterfs.lustre." #name }, { version }, \
446                                -1, 0, 0, 0, 0, name##_start, name##_stop }; \
447                                                                         \
448 __private_extern__ kmod_start_func_t *_realmain = name##_start;         \
449 __private_extern__ kmod_stop_func_t *_antimain = name##_stop;           \
450 __private_extern__ int _kext_apple_cc = __APPLE_CC__ ;                  \
451                                                                         \
452 kern_return_t name##_start(kmod_info_t *ki, void *d)                    \
453 {                                                                       \
454         return init();                                                  \
455 }                                                                       \
456                                                                         \
457 kern_return_t name##_stop(kmod_info_t *ki, void *d)                     \
458 {                                                                       \
459         fini();                                                         \
460         return KERN_SUCCESS;                                            \
461 }                                                                       \
462                                                                         \
463 /*                                                                      \
464  * to allow semicolon after cfs_module(...)                             \
465  */                                                                     \
466 struct __dummy_ ## name ## _struct {}
467
468 #define inter_module_get(n)                     cfs_symbol_get(n)
469 #define inter_module_put(n)                     cfs_symbol_put(n)
470
471 static inline int request_module(const char *name, ...)
472 {
473         return (-EINVAL);
474 }
475
476 #ifndef __exit
477 #define __exit
478 #endif
479 #ifndef __init
480 #define __init
481 #endif
482
483 #define MODULE_AUTHOR(s)
484 #define MODULE_DESCRIPTION(s)
485 #define MODULE_LICENSE(s)
486 #define MODULE_PARM(a, b)
487 #define MODULE_PARM_DESC(a, b)
488
489 #define NR_IRQS                         512
490 #define in_interrupt()                  ml_at_interrupt_context()
491
492 #define KERN_EMERG      "<0>"   /* system is unusable                   */
493 #define KERN_ALERT      "<1>"   /* action must be taken immediately     */
494 #define KERN_CRIT       "<2>"   /* critical conditions                  */
495 #define KERN_ERR        "<3>"   /* error conditions                     */
496 #define KERN_WARNING    "<4>"   /* warning conditions                   */
497 #define KERN_NOTICE     "<5>"   /* normal but significant condition     */
498 #define KERN_INFO       "<6>"   /* informational                        */
499 #define KERN_DEBUG      "<7>"   /* debug-level messages                 */
500
501 static inline long PTR_ERR(const void *ptr)
502 {
503         return (long) ptr;
504 }
505
506 #define ERR_PTR(err)    ((void *)err)
507 #define IS_ERR(p)       ((unsigned long)(p) + 1000 < 1000)
508
509 #else   /* !__KERNEL__ */
510
511 typedef struct cfs_proc_dir_entry {
512         void            *data;
513 } cfs_proc_dir_entry_t;
514
515 #include <libcfs/user-prim.h>
516 #define __WORDSIZE      32
517
518 #endif  /* END __KERNEL__ */
519 /*
520  * Error number
521  */
522 #ifndef EPROTO
523 #define EPROTO          EPROTOTYPE
524 #endif
525 #ifndef EBADR
526 #define EBADR           EBADRPC
527 #endif
528 #ifndef ERESTARTSYS
529 #define ERESTARTSYS     512
530 #endif
531 #ifndef EDEADLOCK
532 #define EDEADLOCK       EDEADLK
533 #endif
534 #ifndef ECOMM
535 #define ECOMM           EINVAL
536 #endif
537 #ifndef ENODATA
538 #define ENODATA         EINVAL
539 #endif
540 #ifndef ENOTSUPP
541 #define ENOTSUPP        EINVAL
542 #endif
543
544 #if BYTE_ORDER == BIG_ENDIAN
545 # define __BIG_ENDIAN
546 #else
547 # define __LITTLE_ENDIAN
548 #endif
549
550 #endif  /* __LIBCFS_DARWIN_CFS_PRIM_H__ */