Merge branch 'master' of https://github.com/bvanassche/fio
[fio.git] / os / os-android.h
1 #ifndef FIO_OS_ANDROID_H
2 #define FIO_OS_ANDROID_H
3
4 #define FIO_OS  os_android
5
6 #include <sys/ioctl.h>
7 #include <sys/mman.h>
8 #include <sys/uio.h>
9 #include <sys/syscall.h>
10 #include <sys/sysmacros.h>
11 #include <sys/vfs.h>
12 #include <unistd.h>
13 #include <fcntl.h>
14 #include <errno.h>
15 #include <sched.h>
16 #include <linux/unistd.h>
17 #include <linux/major.h>
18 #include <asm/byteorder.h>
19
20 #include "./os-linux-syscall.h"
21 #include "../file.h"
22
23 #ifndef __has_builtin         // Optional of course.
24   #define __has_builtin(x) 0  // Compatibility with non-clang compilers.
25 #endif
26
27 #define FIO_HAVE_DISK_UTIL
28 #define FIO_HAVE_IOSCHED_SWITCH
29 #define FIO_HAVE_IOPRIO
30 #define FIO_HAVE_IOPRIO_CLASS
31 #define FIO_HAVE_ODIRECT
32 #define FIO_HAVE_HUGETLB
33 #define FIO_HAVE_BLKTRACE
34 #define FIO_HAVE_CL_SIZE
35 #define FIO_HAVE_CGROUPS
36 #define FIO_HAVE_FS_STAT
37 #define FIO_HAVE_TRIM
38 #define FIO_HAVE_GETTID
39 #define FIO_USE_GENERIC_INIT_RANDOM_STATE
40 #define FIO_HAVE_E4_ENG
41 #define FIO_HAVE_BYTEORDER_FUNCS
42 #define FIO_HAVE_MMAP_HUGE
43 #define FIO_NO_HAVE_SHM_H
44
45 #define OS_MAP_ANON             MAP_ANONYMOUS
46
47 #ifndef POSIX_MADV_DONTNEED
48 #define posix_madvise   madvise
49 #define POSIX_MADV_DONTNEED MADV_DONTNEED
50 #define POSIX_MADV_SEQUENTIAL   MADV_SEQUENTIAL
51 #define POSIX_MADV_RANDOM       MADV_RANDOM
52 #endif
53
54 #ifdef MADV_REMOVE
55 #define FIO_MADV_FREE   MADV_REMOVE
56 #endif
57 #ifndef MAP_HUGETLB
58 #define MAP_HUGETLB 0x40000 /* arch specific */
59 #endif
60
61 #ifdef CONFIG_PTHREAD_GETAFFINITY
62 #define FIO_HAVE_GET_THREAD_AFFINITY
63 #define fio_get_thread_affinity(mask)   \
64         pthread_getaffinity_np(pthread_self(), sizeof(mask), &(mask))
65 #endif
66
67 #ifndef CONFIG_NO_SHM
68 /*
69  * Bionic doesn't support SysV shared memeory, so implement it using ashmem
70  */
71 #include <stdio.h>
72 #include <linux/ashmem.h>
73 #include <linux/shm.h>
74 #include <android/api-level.h>
75 #if __ANDROID_API__ >= __ANDROID_API_O__
76 #include <android/sharedmem.h>
77 #else
78 #define ASHMEM_DEVICE   "/dev/ashmem"
79 #endif
80 #define shmid_ds shmid64_ds
81 #define SHM_HUGETLB    04000
82
83 static inline int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf)
84 {
85         int ret=0;
86         if (__cmd == IPC_RMID)
87         {
88                 int length = ioctl(__shmid, ASHMEM_GET_SIZE, NULL);
89                 struct ashmem_pin pin = {0 , length};
90                 ret = ioctl(__shmid, ASHMEM_UNPIN, &pin);
91                 close(__shmid);
92         }
93         return ret;
94 }
95
96 #if __ANDROID_API__ >= __ANDROID_API_O__
97 static inline int shmget(key_t __key, size_t __size, int __shmflg)
98 {
99         char keybuf[11];
100
101         sprintf(keybuf, "%d", __key);
102
103         return ASharedMemory_create(keybuf, __size + sizeof(uint64_t));
104 }
105 #else
106 static inline int shmget(key_t __key, size_t __size, int __shmflg)
107 {
108         int fd,ret;
109         char keybuf[11];
110
111         fd = open(ASHMEM_DEVICE, O_RDWR);
112         if (fd < 0)
113                 return fd;
114
115         sprintf(keybuf,"%d",__key);
116         ret = ioctl(fd, ASHMEM_SET_NAME, keybuf);
117         if (ret < 0)
118                 goto error;
119
120         /* Stores size in first 8 bytes, allocate extra space */
121         ret = ioctl(fd, ASHMEM_SET_SIZE, __size + sizeof(uint64_t));
122         if (ret < 0)
123                 goto error;
124
125         return fd;
126
127 error:
128         close(fd);
129         return ret;
130 }
131 #endif
132
133 static inline void *shmat(int __shmid, const void *__shmaddr, int __shmflg)
134 {
135         size_t size = ioctl(__shmid, ASHMEM_GET_SIZE, NULL);
136         /* Needs to be 8-byte aligned to prevent SIGBUS on 32-bit ARM */
137         uint64_t *ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, __shmid, 0);
138         /* Save size at beginning of buffer, for use with munmap */
139         *ptr = size;
140         return ptr + 1;
141 }
142
143 static inline int shmdt (const void *__shmaddr)
144 {
145         /* Find mmap size which we stored at the beginning of the buffer */
146         uint64_t *ptr = (uint64_t *)__shmaddr - 1;
147         size_t size = *ptr;
148         return munmap(ptr, size);
149 }
150 #endif
151
152 #define SPLICE_DEF_SIZE (64*1024)
153
154 enum {
155         IOPRIO_CLASS_NONE,
156         IOPRIO_CLASS_RT,
157         IOPRIO_CLASS_BE,
158         IOPRIO_CLASS_IDLE,
159 };
160
161 enum {
162         IOPRIO_WHO_PROCESS = 1,
163         IOPRIO_WHO_PGRP,
164         IOPRIO_WHO_USER,
165 };
166
167 #define IOPRIO_BITS             16
168 #define IOPRIO_CLASS_SHIFT      13
169
170 #define IOPRIO_MIN_PRIO         0       /* highest priority */
171 #define IOPRIO_MAX_PRIO         7       /* lowest priority */
172
173 #define IOPRIO_MIN_PRIO_CLASS   0
174 #define IOPRIO_MAX_PRIO_CLASS   3
175
176 static inline int ioprio_value(int ioprio_class, int ioprio)
177 {
178         /*
179          * If no class is set, assume BE
180          */
181         if (!ioprio_class)
182                 ioprio_class = IOPRIO_CLASS_BE;
183
184         return (ioprio_class << IOPRIO_CLASS_SHIFT) | ioprio;
185 }
186
187 static inline bool ioprio_value_is_class_rt(unsigned int priority)
188 {
189         return (priority >> IOPRIO_CLASS_SHIFT) == IOPRIO_CLASS_RT;
190 }
191
192 static inline int ioprio_set(int which, int who, int ioprio_class, int ioprio)
193 {
194         return syscall(__NR_ioprio_set, which, who,
195                        ioprio_value(ioprio_class, ioprio));
196 }
197
198 #ifndef BLKGETSIZE64
199 #define BLKGETSIZE64    _IOR(0x12,114,size_t)
200 #endif
201
202 #ifndef BLKFLSBUF
203 #define BLKFLSBUF       _IO(0x12,97)
204 #endif
205
206 #ifndef BLKDISCARD
207 #define BLKDISCARD      _IO(0x12,119)
208 #endif
209
210 static inline int blockdev_invalidate_cache(struct fio_file *f)
211 {
212         return ioctl(f->fd, BLKFLSBUF);
213 }
214
215 static inline int blockdev_size(struct fio_file *f, unsigned long long *bytes)
216 {
217         if (!ioctl(f->fd, BLKGETSIZE64, bytes))
218                 return 0;
219
220         return errno;
221 }
222
223 static inline unsigned long long os_phys_mem(void)
224 {
225         long pagesize, pages;
226
227         pagesize = sysconf(_SC_PAGESIZE);
228         pages = sysconf(_SC_PHYS_PAGES);
229         if (pages == -1 || pagesize == -1)
230                 return 0;
231
232         return (unsigned long long) pages * (unsigned long long) pagesize;
233 }
234
235 #ifdef O_NOATIME
236 #define FIO_O_NOATIME   O_NOATIME
237 #else
238 #define FIO_O_NOATIME   0
239 #endif
240
241 /* Check for GCC or Clang byte swap intrinsics */
242 #if (__has_builtin(__builtin_bswap16) && __has_builtin(__builtin_bswap32) \
243      && __has_builtin(__builtin_bswap64)) || (__GNUC__ > 4 \
244      || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) /* fio_swapN */
245 #define fio_swap16(x)   __builtin_bswap16(x)
246 #define fio_swap32(x)   __builtin_bswap32(x)
247 #define fio_swap64(x)   __builtin_bswap64(x)
248 #else
249 #include <byteswap.h>
250 #define fio_swap16(x)   bswap_16(x)
251 #define fio_swap32(x)   bswap_32(x)
252 #define fio_swap64(x)   bswap_64(x)
253 #endif /* fio_swapN */
254
255 #define CACHE_LINE_FILE \
256         "/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size"
257
258 static inline int arch_cache_line_size(void)
259 {
260         char size[32];
261         int fd, ret;
262
263         fd = open(CACHE_LINE_FILE, O_RDONLY);
264         if (fd < 0)
265                 return -1;
266
267         ret = read(fd, size, sizeof(size));
268
269         close(fd);
270
271         if (ret <= 0)
272                 return -1;
273         else
274                 return atoi(size);
275 }
276
277 static inline unsigned long long get_fs_free_size(const char *path)
278 {
279         unsigned long long ret;
280         struct statfs s;
281
282         if (statfs(path, &s) < 0)
283                 return -1ULL;
284
285         ret = s.f_bsize;
286         ret *= (unsigned long long) s.f_bfree;
287         return ret;
288 }
289
290 static inline int os_trim(struct fio_file *f, unsigned long long start,
291                           unsigned long long len)
292 {
293         uint64_t range[2];
294
295         range[0] = start;
296         range[1] = len;
297
298         if (!ioctl(f->fd, BLKDISCARD, range))
299                 return 0;
300
301         return errno;
302 }
303
304 #ifdef CONFIG_SCHED_IDLE
305 static inline int fio_set_sched_idle(void)
306 {
307         struct sched_param p = { .sched_priority = 0, };
308         return sched_setscheduler(gettid(), SCHED_IDLE, &p);
309 }
310 #endif
311
312 #ifndef RWF_UNCACHED
313 #define RWF_UNCACHED    0x00000040
314 #endif
315
316 #endif