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