Merge branch 'master' into client-server
[fio.git] / os / os-mac.h
1 #ifndef FIO_OS_APPLE_H
2 #define FIO_OS_APPLE_H
3
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <sys/disk.h>
7 #include <sys/sysctl.h>
8 #include <sys/time.h>
9 #include <unistd.h>
10 #include <signal.h>
11 #include <mach/mach_init.h>
12 #include <machine/endian.h>
13 #include <libkern/OSByteOrder.h>
14
15 #include "../file.h"
16
17 #ifndef CLOCK_MONOTONIC
18 #define CLOCK_MONOTONIC 1
19 #endif
20
21 #ifndef CLOCK_REALTIME
22 #define CLOCK_REALTIME 1
23 #endif
24
25 #define FIO_HAVE_POSIXAIO
26 #define FIO_HAVE_CLOCK_MONOTONIC
27 #define FIO_USE_GENERIC_RAND
28 #define FIO_HAVE_GETTID
29 #define FIO_HAVE_CHARDEV_SIZE
30
31 #define OS_MAP_ANON             MAP_ANON
32
33 #if defined(__LITTLE_ENDIAN__)
34 #define FIO_LITTLE_ENDIAN
35 #elif defined(__BIG_ENDIAN__)
36 #define FIO_BIG_ENDIAN
37 #else
38 #error "Undefined byte order"
39 #endif
40
41 #define fio_swap16(x)   OSSwapInt16(x)
42 #define fio_swap32(x)   OSSwapInt32(x)
43 #define fio_swap64(x)   OSSwapInt64(x)
44
45 /*
46  * OSX has a pitifully small shared memory segment by default,
47  * so default to a lower number of max jobs supported
48  */
49 #define FIO_MAX_JOBS            128
50
51 typedef off_t off64_t;
52
53 /* OS X as of 10.6 doesn't have the timer_* functions. 
54  * Emulate the functionality using setitimer and sigaction here
55  */
56
57 #define MAX_TIMERS 64
58
59 typedef unsigned int clockid_t;
60 typedef unsigned int timer_t;
61
62 struct itimerspec {
63         struct timespec it_value;
64         struct timespec it_interval;
65 };
66
67 static struct sigevent fio_timers[MAX_TIMERS];
68 static unsigned int num_timers = 0;
69
70 static inline int timer_create(clockid_t clockid, struct sigevent *restrict evp,
71                                  timer_t *restrict timerid)
72 {
73         int current_timer = num_timers;
74         fio_timers[current_timer] = *evp;
75         num_timers++;
76         
77         *timerid = current_timer;
78         return 0;
79 }
80
81 static void sig_alrm(int signum)
82 {
83         union sigval sv;
84         
85         for (int i = 0; i < num_timers; i++) {
86                 if (fio_timers[i].sigev_notify_function == NULL)
87                         continue;
88                 
89                 if (fio_timers[i].sigev_notify == SIGEV_THREAD)
90                         fio_timers[i].sigev_notify_function(sv);
91                 else if (fio_timers[i].sigev_notify == SIGEV_SIGNAL)
92                         kill(getpid(), fio_timers[i].sigev_signo);
93         }
94 }
95
96 static inline int timer_settime(timer_t timerid, int flags,
97                                                                 const struct itimerspec *value, struct itimerspec *ovalue)
98 {
99         struct sigaction sa;
100         struct itimerval tv;
101         struct itimerval tv_out;
102         int rc;
103         
104         tv.it_interval.tv_sec = value->it_interval.tv_sec;
105         tv.it_interval.tv_usec = value->it_interval.tv_nsec / 1000;
106
107         tv.it_value.tv_sec = value->it_value.tv_sec;
108         tv.it_value.tv_usec = value->it_value.tv_nsec / 1000;
109
110         sa.sa_handler = sig_alrm;
111         sigemptyset(&sa.sa_mask);
112         sa.sa_flags = 0;
113         
114         rc = sigaction(SIGALRM, &sa, NULL);
115
116         if (!rc)
117                 rc = setitimer(ITIMER_REAL, &tv, &tv_out);
118         
119         if (!rc && ovalue != NULL) {
120                 ovalue->it_interval.tv_sec = tv_out.it_interval.tv_sec;
121                 ovalue->it_interval.tv_nsec = tv_out.it_interval.tv_usec * 1000;
122                 ovalue->it_value.tv_sec = tv_out.it_value.tv_sec;
123                 ovalue->it_value.tv_nsec = tv_out.it_value.tv_usec * 1000;
124         }
125
126         return rc;
127 }
128
129 static inline int timer_delete(timer_t timer)
130 {
131         return 0;
132 }
133
134 #define FIO_OS_DIRECTIO
135 static inline int fio_set_odirect(int fd)
136 {
137         if (fcntl(fd, F_NOCACHE, 1) == -1)
138                 return errno;
139         return 0;
140 }
141
142 static inline int blockdev_size(struct fio_file *f, unsigned long long *bytes)
143 {
144     uint64_t temp = 1;
145     if (ioctl(f->fd, DKIOCGETBLOCKCOUNT, bytes) == -1)
146                 return errno;
147     if (ioctl(f->fd, DKIOCGETBLOCKSIZE, &temp) == -1)
148                 return errno;
149     (*bytes) *= temp;
150     return 0;
151 }
152
153 static inline int chardev_size(struct fio_file *f, unsigned long long *bytes)
154 {
155         /*
156          * Could be a raw block device, this is better than just assuming
157          * we can't get the size at all.
158          */
159         if (!blockdev_size(f, bytes))
160                 return 0;
161
162         *bytes = -1ULL;
163         return 0;
164 }
165
166 static inline int blockdev_invalidate_cache(struct fio_file *f)
167 {
168         return EINVAL;
169 }
170
171 static inline unsigned long long os_phys_mem(void)
172 {
173         int mib[2] = { CTL_HW, HW_PHYSMEM };
174         unsigned long long mem;
175         size_t len = sizeof(mem);
176
177         sysctl(mib, 2, &mem, &len, NULL, 0);
178         return mem;
179 }
180
181 static inline int gettid(void)
182 {
183         return mach_thread_self();
184 }
185 #endif