| /* |
| * Copyright 2009 The Android Open Source Project |
| * |
| * 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. |
| */ |
| |
| /* Helper to test linux pipe's */ |
| |
| #include <pthread.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <errno.h> |
| #include <unistd.h> |
| #include <sys/poll.h> |
| #include <sys/socket.h> |
| |
| static void print_events(int events) { |
| if (events & POLLIN) printf("POLLIN "); |
| if (events & POLLPRI) printf("POLLPRI "); |
| if (events & POLLOUT) printf("POLLOUT "); |
| if (events & POLLERR) printf("POLLERR "); |
| if (events & POLLHUP) printf("POLLHUP "); |
| if (events & POLLNVAL) printf("POLLNVAL "); |
| printf("\n"); |
| } |
| |
| static int _socketpair(int fd[2]) { |
| int ret; |
| printf("%d: socketpair()\n", gettid()); |
| ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd); |
| printf("%d: socketpair() = %d\n", gettid(), ret); |
| if (ret) printf("\terr %d (%s)\n", errno, strerror(errno)); |
| return ret; |
| } |
| |
| static int _close(int fd) { |
| int ret; |
| printf("%d: close(%d)\n", gettid(), fd); |
| ret = close(fd); |
| printf("%d: close(%d) = %d\n", gettid(), fd, ret); |
| if (ret) printf("\terr %d (%s)\n", errno, strerror(errno)); |
| return ret; |
| } |
| |
| static int _poll(struct pollfd *ufds, nfds_t nfds, int timeout) { |
| int ret; |
| unsigned int i; |
| printf("%d: poll()\n", gettid()); |
| ret = poll(ufds, nfds, timeout); |
| printf("%d: poll() = %d\n", gettid(), ret); |
| if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno)); |
| if (ret > 0) { |
| for (i=0; i<nfds; i++) { |
| if (ufds[i].revents) { |
| printf("\tfd %d ", ufds[i].fd); print_events(ufds[i].revents); |
| } |
| } |
| } |
| return ret; |
| } |
| |
| static int _write(int fd, char *buf, int len) { |
| int ret; |
| |
| printf("%d: write(%d)\n", gettid(), fd); |
| ret = write(fd, buf, len); |
| printf("%d: write(%d) = %d\n", gettid(), fd, ret); |
| if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno)); |
| |
| return ret; |
| } |
| |
| static int _read(int fd) { |
| int ret; |
| char buf; |
| |
| printf("%d: read(%d)\n", gettid(), fd); |
| ret = read(fd, &buf, 1); |
| printf("%d: read(%d) = %d [%d]\n", gettid(), fd, ret, (int)buf); |
| if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno)); |
| |
| return ret; |
| } |
| |
| static int _shutdown(int fd, int how) { |
| int ret; |
| |
| printf("%d: shutdown(%d)\n", gettid(), fd); |
| ret = shutdown(fd, how); |
| printf("%d: shutdown(%d) = %d\n", gettid(), fd, ret); |
| if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno)); |
| |
| return ret; |
| } |
| static void thread_poll(void *args) { |
| int fd = (int)args; |
| struct pollfd pfd; |
| printf("%d: START\n", gettid()); |
| pfd.fd = fd; |
| pfd.events = 0; |
| _poll(&pfd, 1, -1); |
| printf("%d: END\n", gettid()); |
| } |
| |
| static void thread_pollin(void *args) { |
| int fd = (int)args; |
| struct pollfd pfd; |
| printf("%d: START\n", gettid()); |
| pfd.fd = fd; |
| pfd.events = POLLIN; |
| _poll(&pfd, 1, -1); |
| printf("%d: END\n", gettid()); |
| } |
| |
| static void thread_pollin_rand_delay(void *args) { |
| int fd = (int)args; |
| struct pollfd pfd; |
| int delay = (int)((double)random() * (10000000.0 / 2147483647.0)); |
| printf("%d: START (delay = %d)\n", gettid(), delay); |
| pfd.fd = fd; |
| pfd.events = POLLIN; |
| usleep(delay); |
| _poll(&pfd, 1, -1); |
| printf("%d: END\n", gettid()); |
| } |
| |
| static void thread_read(void *args) { |
| int fd = (int)args; |
| printf("%d: START\n", gettid()); |
| _read(fd); |
| printf("%d: END\n", gettid()); |
| } |
| |
| static void thread_close(void *args) { |
| int fd = (int)args; |
| printf("%d: START\n", gettid()); |
| _close(fd); |
| printf("%d: END\n", gettid()); |
| } |
| |
| static int do_poll_poll_close() { |
| pthread_t t1; |
| pthread_t t2; |
| int fd[2]; |
| |
| if (pipe(fd)) return -1; |
| |
| pthread_create(&t1, NULL, (void *)thread_poll, NULL); |
| pthread_create(&t2, NULL, (void *)thread_poll, NULL); |
| |
| sleep(1); |
| |
| _close(fd[1]); |
| |
| pthread_join(t1, NULL); |
| pthread_join(t2, NULL); |
| |
| return 0; |
| } |
| |
| static int do_socketpair_poll1_shutdown2() { |
| int fd[2]; |
| pthread_t t; |
| |
| if (_socketpair(fd)) return -1; |
| |
| pthread_create(&t, NULL, (void *)thread_poll, (void *)fd[1]); |
| |
| sleep(1); |
| |
| _shutdown(fd[0], SHUT_RDWR); |
| |
| sleep(1); |
| |
| _close(fd[0]); |
| |
| pthread_join(t, NULL); |
| |
| return 0; |
| } |
| |
| static int do_socketpair_poll1_shutdown1() { |
| int fd[2]; |
| pthread_t t; |
| |
| if (_socketpair(fd)) return -1; |
| |
| pthread_create(&t, NULL, (void *)thread_poll, (void *)fd[0]); |
| |
| sleep(1); |
| |
| _shutdown(fd[0], SHUT_RDWR); |
| |
| sleep(1); |
| |
| _close(fd[0]); |
| |
| pthread_join(t, NULL); |
| |
| return 0; |
| } |
| |
| static int do_socketpair_poll1_close1() { |
| int fd[2]; |
| pthread_t t; |
| |
| if (_socketpair(fd)) return -1; |
| |
| pthread_create(&t, NULL, (void *)thread_poll, (void *)fd[0]); |
| |
| sleep(1); |
| |
| _close(fd[0]); |
| |
| pthread_join(t, NULL); |
| |
| return 0; |
| } |
| |
| static int do_socketpair_read1_shutdown1() { |
| int fd[2]; |
| pthread_t t; |
| |
| if (_socketpair(fd)) return -1; |
| |
| pthread_create(&t, NULL, (void *)thread_read, (void *)fd[0]); |
| |
| sleep(1); |
| |
| _shutdown(fd[0], SHUT_RDWR); |
| |
| sleep(1); |
| |
| _close(fd[0]); |
| |
| pthread_join(t, NULL); |
| |
| return 0; |
| } |
| |
| static int do_pipe_pipe_pipe() { |
| int fd[2]; |
| int i; |
| |
| while (1) { |
| if (pipe(fd)) { |
| printf("pipe: %s\n", strerror(errno)); |
| return -1; |
| } |
| printf("%d %d\n", fd[0], fd[1]); |
| close(fd[0]); |
| close(fd[1]); |
| } |
| |
| return 0; |
| } |
| static int do_pollin_pollin_write() { |
| pthread_t t1; |
| pthread_t t2; |
| int fd[2]; |
| char buf = 'a'; |
| int i; |
| |
| if (pipe(fd)) return -1; |
| |
| pthread_create(&t1, NULL, (void *)thread_pollin, (void *)fd[0]); |
| pthread_create(&t2, NULL, (void *)thread_pollin, (void *)fd[0]); |
| |
| sleep(1); |
| |
| for (i = 0; i < 100; i++) |
| _write(fd[1], &buf, 1); |
| |
| pthread_join(t1, NULL); |
| pthread_join(t2, NULL); |
| |
| return 0; |
| } |
| |
| static int do_pollin_pollin_pollin_write_pollin_pollin_pollin() { |
| const int MAX_T = 10; |
| pthread_t t[MAX_T]; |
| int fd[2]; |
| char buf = 'a'; |
| int i; |
| |
| if (pipe(fd)) return -1; |
| |
| for (i=0; i<MAX_T; i++) |
| pthread_create(&t[i], NULL, (void *)thread_pollin_rand_delay, (void *)fd[0]); |
| |
| sleep(5); |
| |
| _write(fd[1], &buf, 1); |
| |
| for (i=0; i<MAX_T; i++) |
| pthread_join(t[i], NULL); |
| |
| _close(fd[0]); |
| _close(fd[1]); |
| |
| return 0; |
| } |
| |
| static int do_poll_poll_shutdown() { |
| #if 0 |
| pthread_t t1; |
| pthread_t t2; |
| int fd[2]; |
| |
| if (pipe(fd)) return -1; |
| |
| pthread_create(&t1, NULL, (void *)thread_poll, (void *)fd[0]); |
| pthread_create(&t2, NULL, (void *)thread_poll, (void *)fd[0]); |
| |
| sleep(1); |
| |
| _shutdown(fd[1], SHUT_RDWR); |
| |
| pthread_join(t1, NULL); |
| pthread_join(t2, NULL); |
| #endif |
| |
| return -1; |
| } |
| |
| static int THREADS = 100; |
| |
| static int do_close_poll_poll_poll() { |
| pthread_t t[THREADS]; |
| int i; |
| int fd[2]; |
| |
| if (pipe(fd)) return -1; |
| |
| _close(fd[1]); |
| |
| for (i = 0; i < THREADS; i++) |
| pthread_create(&t[i], NULL, (void *)thread_poll, (void *)fd[0]); |
| |
| for (i = 0; i < THREADS; i++) |
| pthread_join(t[i], NULL); |
| |
| return 0; |
| } |
| |
| static int do_close_close_close() { |
| pthread_t t[THREADS]; |
| int i; |
| int fd[2]; |
| |
| if (pipe(fd)) return -1; |
| |
| for (i = 0; i < THREADS; i++) |
| pthread_create(&t[i], NULL, (void *)thread_close, (void *)fd[i%2]); |
| |
| return 0; |
| } |
| |
| static int pipe_close_w_close_r_repeat() { |
| int fd[2]; |
| pthread_t t; |
| int i; |
| |
| for (i = 0; i < THREADS; i++) { |
| if (pipe(fd)) return -1; |
| pthread_create(&t, NULL, (void *)thread_poll, (void *)fd[0]); |
| _close(fd[1]); |
| _close(fd[0]); |
| pthread_join(t, NULL); |
| } |
| |
| return 0; |
| } |
| |
| struct { |
| char *name; |
| int (*ptr)(); |
| } function_table[] = { |
| {"socketpair_poll1_shutdown2", do_socketpair_poll1_shutdown2}, |
| {"socketpair_poll1_shutdown1", do_socketpair_poll1_shutdown1}, |
| {"socketpair_poll1_close1", do_socketpair_poll1_close1}, |
| {"socketpair_read1_shutdown1", do_socketpair_read1_shutdown1}, |
| {"pipe_pipe_pipe", do_pipe_pipe_pipe}, |
| {"poll_poll_close", do_poll_poll_close}, |
| {"pollin_pollin_write", do_pollin_pollin_write}, |
| {"pollin_pollin_pollin_write_pollin_pollin_pollin", do_pollin_pollin_pollin_write_pollin_pollin_pollin}, |
| {"poll_poll_shutdown", do_poll_poll_shutdown}, |
| {"close_poll_poll_poll", do_close_poll_poll_poll}, |
| {"close_close_close", do_close_close_close}, |
| {"pipe_close_w_close_w_repeat", pipe_close_w_close_r_repeat}, |
| {NULL, NULL}, |
| }; |
| |
| static void usage() { |
| int i; |
| |
| printf("Usage:\n"); |
| for (i = 0; function_table[i].name; i++) { |
| printf("\tpipetest %s\n", function_table[i].name); |
| } |
| } |
| |
| int main(int argc, char **argv) { |
| int i; |
| |
| if (argc != 2) { |
| usage(); |
| return -1; |
| } |
| for (i = 0; function_table[i].name; i++) { |
| if (!strcmp(argv[1], function_table[i].name)) { |
| printf("%s\n", function_table[i].name); |
| return (*function_table[i].ptr)(); |
| } |
| } |
| usage(); |
| return -1; |
| } |