Home | History | Annotate | Download | only in libion
      1 /*
      2  *   Copyright 2013 Google, Inc
      3  *
      4  *  Licensed under the Apache License, Version 2.0 (the "License");
      5  *  you may not use this file except in compliance with the License.
      6  *  You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  *  Unless required by applicable law or agreed to in writing, software
     11  *  distributed under the License is distributed on an "AS IS" BASIS,
     12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  *  See the License for the specific language governing permissions and
     14  *  limitations under the License.
     15  */
     16 
     17 #include <errno.h>
     18 #include <fcntl.h>
     19 #include <getopt.h>
     20 #include <string.h>
     21 #include <stdlib.h>
     22 #include <stdio.h>
     23 #include <sys/mman.h>
     24 #include <sys/ioctl.h>
     25 #include <sys/socket.h>
     26 #include <sys/stat.h>
     27 #include <sys/types.h>
     28 #include <unistd.h>
     29 
     30 #include <ion/ion.h>
     31 #include <linux/ion.h>
     32 
     33 size_t len = 1024*1024, align = 0;
     34 int prot = PROT_READ | PROT_WRITE;
     35 int map_flags = MAP_SHARED;
     36 int alloc_flags = 0;
     37 int heap_mask = 1;
     38 int test = -1;
     39 size_t stride;
     40 
     41 int _ion_alloc_test(int *fd, ion_user_handle_t *handle)
     42 {
     43     int ret;
     44 
     45     *fd = ion_open();
     46     if (*fd < 0)
     47         return *fd;
     48 
     49     ret = ion_alloc(*fd, len, align, heap_mask, alloc_flags, handle);
     50 
     51     if (ret)
     52         printf("%s failed: %s\n", __func__, strerror(ret));
     53     return ret;
     54 }
     55 
     56 void ion_alloc_test()
     57 {
     58     int fd, ret;
     59     ion_user_handle_t handle;
     60 
     61     if(_ion_alloc_test(&fd, &handle))
     62         return;
     63 
     64     ret = ion_free(fd, handle);
     65     if (ret) {
     66         printf("%s failed: %s %d\n", __func__, strerror(ret), handle);
     67         return;
     68     }
     69     ion_close(fd);
     70     printf("ion alloc test: passed\n");
     71 }
     72 
     73 void ion_map_test()
     74 {
     75     int fd, map_fd, ret;
     76     size_t i;
     77     ion_user_handle_t handle;
     78     unsigned char *ptr;
     79 
     80     if(_ion_alloc_test(&fd, &handle))
     81         return;
     82 
     83     ret = ion_map(fd, handle, len, prot, map_flags, 0, &ptr, &map_fd);
     84     if (ret)
     85         return;
     86 
     87     for (i = 0; i < len; i++) {
     88         ptr[i] = (unsigned char)i;
     89     }
     90     for (i = 0; i < len; i++)
     91         if (ptr[i] != (unsigned char)i)
     92             printf("%s failed wrote %zu read %d from mapped "
     93                    "memory\n", __func__, i, ptr[i]);
     94     /* clean up properly */
     95     ret = ion_free(fd, handle);
     96     ion_close(fd);
     97     munmap(ptr, len);
     98     close(map_fd);
     99 
    100     _ion_alloc_test(&fd, &handle);
    101     close(fd);
    102 
    103 #if 0
    104     munmap(ptr, len);
    105     close(map_fd);
    106     ion_close(fd);
    107 
    108     _ion_alloc_test(len, align, flags, &fd, &handle);
    109     close(map_fd);
    110     ret = ion_map(fd, handle, len, prot, flags, 0, &ptr, &map_fd);
    111     /* don't clean up */
    112 #endif
    113 }
    114 
    115 void ion_share_test()
    116 
    117 {
    118     ion_user_handle_t handle;
    119     int sd[2];
    120     int num_fd = 1;
    121     struct iovec count_vec = {
    122         .iov_base = &num_fd,
    123         .iov_len = sizeof num_fd,
    124     };
    125     char buf[CMSG_SPACE(sizeof(int))];
    126     socketpair(AF_UNIX, SOCK_STREAM, 0, sd);
    127     if (fork()) {
    128         struct msghdr msg = {
    129             .msg_control = buf,
    130             .msg_controllen = sizeof buf,
    131             .msg_iov = &count_vec,
    132             .msg_iovlen = 1,
    133         };
    134 
    135         struct cmsghdr *cmsg;
    136         int fd, share_fd, ret;
    137         char *ptr;
    138         /* parent */
    139         if(_ion_alloc_test(&fd, &handle))
    140             return;
    141         ret = ion_share(fd, handle, &share_fd);
    142         if (ret)
    143             printf("share failed %s\n", strerror(errno));
    144         ptr = mmap(NULL, len, prot, map_flags, share_fd, 0);
    145         if (ptr == MAP_FAILED) {
    146             return;
    147         }
    148         strcpy(ptr, "master");
    149         cmsg = CMSG_FIRSTHDR(&msg);
    150         cmsg->cmsg_level = SOL_SOCKET;
    151         cmsg->cmsg_type = SCM_RIGHTS;
    152         cmsg->cmsg_len = CMSG_LEN(sizeof(int));
    153         *(int *)CMSG_DATA(cmsg) = share_fd;
    154         /* send the fd */
    155         printf("master? [%10s] should be [master]\n", ptr);
    156         printf("master sending msg 1\n");
    157         sendmsg(sd[0], &msg, 0);
    158         if (recvmsg(sd[0], &msg, 0) < 0)
    159             perror("master recv msg 2");
    160         printf("master? [%10s] should be [child]\n", ptr);
    161 
    162         /* send ping */
    163         sendmsg(sd[0], &msg, 0);
    164         printf("master->master? [%10s]\n", ptr);
    165         if (recvmsg(sd[0], &msg, 0) < 0)
    166             perror("master recv 1");
    167     } else {
    168         struct msghdr msg;
    169         struct cmsghdr *cmsg;
    170         char* ptr;
    171         int fd, recv_fd;
    172         char* child_buf[100];
    173         /* child */
    174         struct iovec count_vec = {
    175             .iov_base = child_buf,
    176             .iov_len = sizeof child_buf,
    177         };
    178 
    179         struct msghdr child_msg = {
    180             .msg_control = buf,
    181             .msg_controllen = sizeof buf,
    182             .msg_iov = &count_vec,
    183             .msg_iovlen = 1,
    184         };
    185 
    186         if (recvmsg(sd[1], &child_msg, 0) < 0)
    187             perror("child recv msg 1");
    188         cmsg = CMSG_FIRSTHDR(&child_msg);
    189         if (cmsg == NULL) {
    190             printf("no cmsg rcvd in child");
    191             return;
    192         }
    193         recv_fd = *(int*)CMSG_DATA(cmsg);
    194         if (recv_fd < 0) {
    195             printf("could not get recv_fd from socket");
    196             return;
    197         }
    198         printf("child %d\n", recv_fd);
    199         fd = ion_open();
    200         ptr = mmap(NULL, len, prot, map_flags, recv_fd, 0);
    201         if (ptr == MAP_FAILED) {
    202             return;
    203         }
    204         printf("child? [%10s] should be [master]\n", ptr);
    205         strcpy(ptr, "child");
    206         printf("child sending msg 2\n");
    207         sendmsg(sd[1], &child_msg, 0);
    208     }
    209 }
    210 
    211 int main(int argc, char* argv[]) {
    212     int c;
    213     enum tests {
    214         ALLOC_TEST = 0, MAP_TEST, SHARE_TEST,
    215     };
    216 
    217     while (1) {
    218         static struct option opts[] = {
    219             {"alloc", no_argument, 0, 'a'},
    220             {"alloc_flags", required_argument, 0, 'f'},
    221             {"heap_mask", required_argument, 0, 'h'},
    222             {"map", no_argument, 0, 'm'},
    223             {"share", no_argument, 0, 's'},
    224             {"len", required_argument, 0, 'l'},
    225             {"align", required_argument, 0, 'g'},
    226             {"map_flags", required_argument, 0, 'z'},
    227             {"prot", required_argument, 0, 'p'},
    228         };
    229         int i = 0;
    230         c = getopt_long(argc, argv, "af:h:l:mr:st", opts, &i);
    231         if (c == -1)
    232             break;
    233 
    234         switch (c) {
    235         case 'l':
    236             len = atol(optarg);
    237             break;
    238         case 'g':
    239             align = atol(optarg);
    240             break;
    241         case 'z':
    242             map_flags = 0;
    243             map_flags |= strstr(optarg, "PROT_EXEC") ? PROT_EXEC : 0;
    244             map_flags |= strstr(optarg, "PROT_READ") ? PROT_READ: 0;
    245             map_flags |= strstr(optarg, "PROT_WRITE") ? PROT_WRITE: 0;
    246             map_flags |= strstr(optarg, "PROT_NONE") ? PROT_NONE: 0;
    247             break;
    248         case 'p':
    249             prot = 0;
    250             prot |= strstr(optarg, "MAP_PRIVATE") ? MAP_PRIVATE : 0;
    251             prot |= strstr(optarg, "MAP_SHARED") ? MAP_PRIVATE : 0;
    252             break;
    253         case 'f':
    254             alloc_flags = atol(optarg);
    255             break;
    256         case 'h':
    257             heap_mask = atol(optarg);
    258             break;
    259         case 'a':
    260             test = ALLOC_TEST;
    261             break;
    262         case 'm':
    263             test = MAP_TEST;
    264             break;
    265         case 's':
    266             test = SHARE_TEST;
    267             break;
    268         }
    269     }
    270     printf("test %d, len %zu, align %zu, map_flags %d, prot %d, heap_mask %d,"
    271            " alloc_flags %d\n", test, len, align, map_flags, prot,
    272            heap_mask, alloc_flags);
    273     switch (test) {
    274         case ALLOC_TEST:
    275             ion_alloc_test();
    276             break;
    277         case MAP_TEST:
    278             ion_map_test();
    279             break;
    280         case SHARE_TEST:
    281             ion_share_test();
    282             break;
    283         default:
    284             printf("must specify a test (alloc, map, share)\n");
    285     }
    286     return 0;
    287 }
    288