You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
289 lines
7.7 KiB
289 lines
7.7 KiB
/* |
|
* Copyright 2013 Google, Inc |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
*/ |
|
|
|
#include <errno.h> |
|
#include <fcntl.h> |
|
#include <getopt.h> |
|
#include <string.h> |
|
#include <stdlib.h> |
|
#include <stdio.h> |
|
#include <sys/mman.h> |
|
#include <sys/ioctl.h> |
|
#include <sys/socket.h> |
|
#include <sys/stat.h> |
|
#include <sys/types.h> |
|
#include <unistd.h> |
|
|
|
#include <ion/ion.h> |
|
#include <linux/ion.h> |
|
|
|
size_t len = 1024*1024, align = 0; |
|
int prot = PROT_READ | PROT_WRITE; |
|
int map_flags = MAP_SHARED; |
|
int alloc_flags = 0; |
|
int heap_mask = 1; |
|
int test = -1; |
|
size_t stride; |
|
|
|
int _ion_alloc_test(int *fd, ion_user_handle_t *handle) |
|
{ |
|
int ret; |
|
|
|
*fd = ion_open(); |
|
if (*fd < 0) |
|
return *fd; |
|
|
|
ret = ion_alloc(*fd, len, align, heap_mask, alloc_flags, handle); |
|
|
|
if (ret) |
|
printf("%s failed: %s\n", __func__, strerror(ret)); |
|
return ret; |
|
} |
|
|
|
void ion_alloc_test() |
|
{ |
|
int fd, ret; |
|
ion_user_handle_t handle; |
|
|
|
if(_ion_alloc_test(&fd, &handle)) |
|
return; |
|
|
|
ret = ion_free(fd, handle); |
|
if (ret) { |
|
printf("%s failed: %s %d\n", __func__, strerror(ret), handle); |
|
return; |
|
} |
|
ion_close(fd); |
|
printf("ion alloc test: passed\n"); |
|
} |
|
|
|
void ion_map_test() |
|
{ |
|
int fd, map_fd, ret; |
|
size_t i; |
|
ion_user_handle_t handle; |
|
unsigned char *ptr; |
|
|
|
if(_ion_alloc_test(&fd, &handle)) |
|
return; |
|
|
|
ret = ion_map(fd, handle, len, prot, map_flags, 0, &ptr, &map_fd); |
|
if (ret) |
|
return; |
|
|
|
for (i = 0; i < len; i++) { |
|
ptr[i] = (unsigned char)i; |
|
} |
|
for (i = 0; i < len; i++) |
|
if (ptr[i] != (unsigned char)i) |
|
printf("%s failed wrote %zu read %d from mapped " |
|
"memory\n", __func__, i, ptr[i]); |
|
/* clean up properly */ |
|
ret = ion_free(fd, handle); |
|
ion_close(fd); |
|
munmap(ptr, len); |
|
close(map_fd); |
|
|
|
_ion_alloc_test(&fd, &handle); |
|
close(fd); |
|
|
|
#if 0 |
|
munmap(ptr, len); |
|
close(map_fd); |
|
ion_close(fd); |
|
|
|
_ion_alloc_test(len, align, flags, &fd, &handle); |
|
close(map_fd); |
|
ret = ion_map(fd, handle, len, prot, flags, 0, &ptr, &map_fd); |
|
/* don't clean up */ |
|
#endif |
|
} |
|
|
|
void ion_share_test() |
|
|
|
{ |
|
ion_user_handle_t handle; |
|
int sd[2]; |
|
int num_fd = 1; |
|
struct iovec count_vec = { |
|
.iov_base = &num_fd, |
|
.iov_len = sizeof num_fd, |
|
}; |
|
char buf[CMSG_SPACE(sizeof(int))]; |
|
socketpair(AF_UNIX, SOCK_STREAM, 0, sd); |
|
if (fork()) { |
|
struct msghdr msg = { |
|
.msg_control = buf, |
|
.msg_controllen = sizeof buf, |
|
.msg_iov = &count_vec, |
|
.msg_iovlen = 1, |
|
}; |
|
|
|
struct cmsghdr *cmsg; |
|
int fd, share_fd, ret; |
|
char *ptr; |
|
/* parent */ |
|
if(_ion_alloc_test(&fd, &handle)) |
|
return; |
|
ret = ion_share(fd, handle, &share_fd); |
|
if (ret) |
|
printf("share failed %s\n", strerror(errno)); |
|
ptr = mmap(NULL, len, prot, map_flags, share_fd, 0); |
|
if (ptr == MAP_FAILED) { |
|
return; |
|
} |
|
strcpy(ptr, "master"); |
|
cmsg = CMSG_FIRSTHDR(&msg); |
|
cmsg->cmsg_level = SOL_SOCKET; |
|
cmsg->cmsg_type = SCM_RIGHTS; |
|
cmsg->cmsg_len = CMSG_LEN(sizeof(int)); |
|
*(int *)CMSG_DATA(cmsg) = share_fd; |
|
/* send the fd */ |
|
printf("master? [%10s] should be [master]\n", ptr); |
|
printf("master sending msg 1\n"); |
|
sendmsg(sd[0], &msg, 0); |
|
if (recvmsg(sd[0], &msg, 0) < 0) |
|
perror("master recv msg 2"); |
|
printf("master? [%10s] should be [child]\n", ptr); |
|
|
|
/* send ping */ |
|
sendmsg(sd[0], &msg, 0); |
|
printf("master->master? [%10s]\n", ptr); |
|
if (recvmsg(sd[0], &msg, 0) < 0) |
|
perror("master recv 1"); |
|
close(fd); |
|
_exit(0); |
|
} else { |
|
struct cmsghdr *cmsg; |
|
char* ptr; |
|
int fd, recv_fd; |
|
char* child_buf[100]; |
|
/* child */ |
|
struct iovec count_vec = { |
|
.iov_base = child_buf, |
|
.iov_len = sizeof child_buf, |
|
}; |
|
|
|
struct msghdr child_msg = { |
|
.msg_control = buf, |
|
.msg_controllen = sizeof buf, |
|
.msg_iov = &count_vec, |
|
.msg_iovlen = 1, |
|
}; |
|
|
|
if (recvmsg(sd[1], &child_msg, 0) < 0) |
|
perror("child recv msg 1"); |
|
cmsg = CMSG_FIRSTHDR(&child_msg); |
|
if (cmsg == NULL) { |
|
printf("no cmsg rcvd in child"); |
|
return; |
|
} |
|
recv_fd = *(int*)CMSG_DATA(cmsg); |
|
if (recv_fd < 0) { |
|
printf("could not get recv_fd from socket"); |
|
return; |
|
} |
|
printf("child %d\n", recv_fd); |
|
fd = ion_open(); |
|
ptr = mmap(NULL, len, prot, map_flags, recv_fd, 0); |
|
if (ptr == MAP_FAILED) { |
|
return; |
|
} |
|
printf("child? [%10s] should be [master]\n", ptr); |
|
strcpy(ptr, "child"); |
|
printf("child sending msg 2\n"); |
|
sendmsg(sd[1], &child_msg, 0); |
|
close(fd); |
|
} |
|
} |
|
|
|
int main(int argc, char* argv[]) { |
|
int c; |
|
enum tests { |
|
ALLOC_TEST = 0, MAP_TEST, SHARE_TEST, |
|
}; |
|
|
|
while (1) { |
|
static struct option opts[] = { |
|
{"alloc", no_argument, 0, 'a'}, |
|
{"alloc_flags", required_argument, 0, 'f'}, |
|
{"heap_mask", required_argument, 0, 'h'}, |
|
{"map", no_argument, 0, 'm'}, |
|
{"share", no_argument, 0, 's'}, |
|
{"len", required_argument, 0, 'l'}, |
|
{"align", required_argument, 0, 'g'}, |
|
{"map_flags", required_argument, 0, 'z'}, |
|
{"prot", required_argument, 0, 'p'}, |
|
}; |
|
int i = 0; |
|
c = getopt_long(argc, argv, "af:h:l:mr:st", opts, &i); |
|
if (c == -1) |
|
break; |
|
|
|
switch (c) { |
|
case 'l': |
|
len = atol(optarg); |
|
break; |
|
case 'g': |
|
align = atol(optarg); |
|
break; |
|
case 'z': |
|
map_flags = 0; |
|
map_flags |= strstr(optarg, "PROT_EXEC") ? PROT_EXEC : 0; |
|
map_flags |= strstr(optarg, "PROT_READ") ? PROT_READ: 0; |
|
map_flags |= strstr(optarg, "PROT_WRITE") ? PROT_WRITE: 0; |
|
map_flags |= strstr(optarg, "PROT_NONE") ? PROT_NONE: 0; |
|
break; |
|
case 'p': |
|
prot = 0; |
|
prot |= strstr(optarg, "MAP_PRIVATE") ? MAP_PRIVATE : 0; |
|
prot |= strstr(optarg, "MAP_SHARED") ? MAP_PRIVATE : 0; |
|
break; |
|
case 'f': |
|
alloc_flags = atol(optarg); |
|
break; |
|
case 'h': |
|
heap_mask = atol(optarg); |
|
break; |
|
case 'a': |
|
test = ALLOC_TEST; |
|
break; |
|
case 'm': |
|
test = MAP_TEST; |
|
break; |
|
case 's': |
|
test = SHARE_TEST; |
|
break; |
|
} |
|
} |
|
printf("test %d, len %zu, align %zu, map_flags %d, prot %d, heap_mask %d," |
|
" alloc_flags %d\n", test, len, align, map_flags, prot, |
|
heap_mask, alloc_flags); |
|
switch (test) { |
|
case ALLOC_TEST: |
|
ion_alloc_test(); |
|
break; |
|
case MAP_TEST: |
|
ion_map_test(); |
|
break; |
|
case SHARE_TEST: |
|
ion_share_test(); |
|
break; |
|
default: |
|
printf("must specify a test (alloc, map, share)\n"); |
|
} |
|
return 0; |
|
}
|
|
|