os: introduce ioprio_value() helper
[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 int ioprio_set(int which, int who, int ioprio_class, int ioprio)
188 {
189         return syscall(__NR_ioprio_set, which, who,
190                        ioprio_value(ioprio_class, ioprio));
191 }
192
193 #ifndef BLKGETSIZE64
194 #define BLKGETSIZE64    _IOR(0x12,114,size_t)
195 #endif
196
197 #ifndef BLKFLSBUF
198 #define BLKFLSBUF       _IO(0x12,97)
199 #endif
200
201 #ifndef BLKDISCARD
202 #define BLKDISCARD      _IO(0x12,119)
203 #endif
204
205 static inline int blockdev_invalidate_cache(struct fio_file *f)
206 {
207         return ioctl(f->fd, BLKFLSBUF);
208 }
209
210 static inline int blockdev_size(struct fio_file *f, unsigned long long *bytes)
211 {
212         if (!ioctl(f->fd, BLKGETSIZE64, bytes))
213                 return 0;
214
215         return errno;
216 }
217
218 static inline unsigned long long os_phys_mem(void)
219 {
220         long pagesize, pages;
221
222         pagesize = sysconf(_SC_PAGESIZE);
223         pages = sysconf(_SC_PHYS_PAGES);
224         if (pages == -1 || pagesize == -1)
225                 return 0;
226
227         return (unsigned long long) pages * (unsigned long long) pagesize;
228 }
229
230 #ifdef O_NOATIME
231 #define FIO_O_NOATIME   O_NOATIME
232 #else
233 #define FIO_O_NOATIME   0
234 #endif
235
236 /* Check for GCC or Clang byte swap intrinsics */
237 #if (__has_builtin(__builtin_bswap16) && __has_builtin(__builtin_bswap32) \
238      && __has_builtin(__builtin_bswap64)) || (__GNUC__ > 4 \
239      || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) /* fio_swapN */
240 #define fio_swap16(x)   __builtin_bswap16(x)
241 #define fio_swap32(x)   __builtin_bswap32(x)
242 #define fio_swap64(x)   __builtin_bswap64(x)
243 #else
244 #include <byteswap.h>
245 #define fio_swap16(x)   bswap_16(x)
246 #define fio_swap32(x)   bswap_32(x)
247 #define fio_swap64(x)   bswap_64(x)
248 #endif /* fio_swapN */
249
250 #define CACHE_LINE_FILE \
251         "/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size"
252
253 static inline int arch_cache_line_size(void)
254 {
255         char size[32];
256         int fd, ret;
257
258         fd = open(CACHE_LINE_FILE, O_RDONLY);
259         if (fd < 0)
260                 return -1;
261
262         ret = read(fd, size, sizeof(size));
263
264         close(fd);
265
266         if (ret <= 0)
267                 return -1;
268         else
269                 return atoi(size);
270 }
271
272 static inline unsigned long long get_fs_free_size(const char *path)
273 {
274         unsigned long long ret;
275         struct statfs s;
276
277         if (statfs(path, &s) < 0)
278                 return -1ULL;
279
280         ret = s.f_bsize;
281         ret *= (unsigned long long) s.f_bfree;
282         return ret;
283 }
284
285 static inline int os_trim(struct fio_file *f, unsigned long long start,
286                           unsigned long long len)
287 {
288         uint64_t range[2];
289
290         range[0] = start;
291         range[1] = len;
292
293         if (!ioctl(f->fd, BLKDISCARD, range))
294                 return 0;
295
296         return errno;
297 }
298
299 #ifdef CONFIG_SCHED_IDLE
300 static inline int fio_set_sched_idle(void)
301 {
302         struct sched_param p = { .sched_priority = 0, };
303         return sched_setscheduler(gettid(), SCHED_IDLE, &p);
304 }
305 #endif
306
307 #endif