|  | /* Copyright (c) 2015 Google Inc | 
|  | * Barret Rhoden <brho@cs.berkeley.edu> | 
|  | * See LICENSE for details. | 
|  | * | 
|  | * #eventfd test, using the glibc interface mostly. */ | 
|  |  | 
|  | #include <stdlib.h> | 
|  | #include <stdio.h> | 
|  | #include <parlib/parlib.h> | 
|  | #include <unistd.h> | 
|  | #include <pthread.h> | 
|  |  | 
|  | #include <sys/types.h> | 
|  | #include <sys/stat.h> | 
|  | #include <fcntl.h> | 
|  | #include <sys/eventfd.h> | 
|  | #include <sys/epoll.h> | 
|  |  | 
|  |  | 
|  | #define handle_error(msg) \ | 
|  | do { perror(msg); exit(-1); } while (0) | 
|  |  | 
|  | static void epoll_on_efd(int efd) | 
|  | { | 
|  | #define EP_SET_SZ 10	/* this is actually the ID of the largest FD */ | 
|  | int epfd = epoll_create(EP_SET_SZ); | 
|  | struct epoll_event ep_ev; | 
|  | struct epoll_event results[EP_SET_SZ]; | 
|  |  | 
|  | if (epfd < 0) | 
|  | handle_error("epoll_create"); | 
|  | ep_ev.events = EPOLLIN | EPOLLET; | 
|  | ep_ev.data.fd = efd; | 
|  | if (epoll_ctl(epfd, EPOLL_CTL_ADD, efd, &ep_ev)) | 
|  | handle_error("epoll_ctl_add eventfd"); | 
|  | if (epoll_wait(epfd, results, EP_SET_SZ, -1) != 1) | 
|  | handle_error("epoll_wait"); | 
|  | close(epfd); | 
|  | } | 
|  |  | 
|  | static pthread_attr_t pth_attrs; | 
|  | static bool upped; | 
|  |  | 
|  | static void *upper_thread(void *arg) | 
|  | { | 
|  | int efd = (int)(long)arg; | 
|  | uthread_sleep(1); | 
|  | if (eventfd_write(efd, 1)) | 
|  | handle_error("upper write"); | 
|  | upped = TRUE; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int main(int argc, char **argv) | 
|  | { | 
|  | int ret; | 
|  | eventfd_t efd_val = 0; | 
|  | int efd; | 
|  | pthread_t child; | 
|  |  | 
|  | parlib_wants_to_be_mcp = FALSE; /* Make us an SCP with a 2LS */ | 
|  | pthread_attr_init(&pth_attrs); | 
|  | if (pthread_attr_setdetachstate(&pth_attrs, PTHREAD_CREATE_DETACHED)) | 
|  | handle_error("pth attrs"); | 
|  |  | 
|  | /* Semaphore counter, nonblocking */ | 
|  | efd = eventfd(2, EFD_SEMAPHORE | EFD_NONBLOCK); | 
|  | if (efd < 0) | 
|  | handle_error("open sem"); | 
|  | if (eventfd_read(efd, &efd_val)) | 
|  | handle_error("first read"); | 
|  | assert(efd_val == 1); | 
|  | if (eventfd_read(efd, &efd_val)) | 
|  | handle_error("second read"); | 
|  | assert(efd_val == 1);	/* always get 1 back from the SEM */ | 
|  | ret = eventfd_read(efd, &efd_val); | 
|  | if ((ret != -1) && (errno != EAGAIN)) | 
|  | handle_error("third read should be EAGAIN"); | 
|  |  | 
|  | if (pthread_create(&child, &pth_attrs, &upper_thread, (void*)(long)efd)) | 
|  | handle_error("pth_create failed"); | 
|  | epoll_on_efd(efd); | 
|  | if (eventfd_read(efd, &efd_val)) | 
|  | handle_error("final read"); | 
|  | assert(efd_val == 1); | 
|  | close(efd); | 
|  |  | 
|  | /* Regular counter */ | 
|  | efd = eventfd(2, 0); | 
|  | if (efd < 0) | 
|  | handle_error("open nonsem"); | 
|  | if (eventfd_read(efd, &efd_val)) | 
|  | handle_error("first read nonsem"); | 
|  | assert(efd_val == 2); | 
|  |  | 
|  | /* Will try to block in the kernel.  Using 'upped' to catch any quick | 
|  | * returns.  It's not full-proof, but it can catch an O_NONBLOCK */ | 
|  | if (pthread_create(&child, &pth_attrs, &upper_thread, (void*)(long)efd)) | 
|  | handle_error("pth_create failed"); | 
|  | upped = FALSE; | 
|  | if (eventfd_read(efd, &efd_val)) | 
|  | handle_error("blocking read nonsem"); | 
|  | cmb(); | 
|  | assert(upped && efd_val == 1); | 
|  |  | 
|  | /* Should still be 0.  Add 1 and then extract to see if it was. */ | 
|  | if (eventfd_write(efd, 1)) | 
|  | handle_error("write nonsem +1"); | 
|  | if (eventfd_read(efd, &efd_val)) | 
|  | handle_error("final read nonsem"); | 
|  | /* 1 means it was 0 before we added 1.  it's 0 again, since we read. */ | 
|  | assert(efd_val == 1); | 
|  | /* Test the max_val + 1 write */ | 
|  | ret = eventfd_write(efd, -1); | 
|  | if ((ret != -1) && (errno != EINVAL)) | 
|  | handle_error("write nonsem should have failed"); | 
|  | if (eventfd_write(efd, 0xfffffffffffffffe)) | 
|  | handle_error("largest legal write"); | 
|  | close(efd); | 
|  |  | 
|  | return 0; | 
|  | } |