# FIFO, poll, epoll
<style>
.blue {
color: blue;
}
.bgblue {
color: blue;
font-size: 24px;
font-weight: bold;
}
.red {
color: red;
font-size: 24px;
font-weight: bold;
}
h1 {text-align: center;}
h2 {text-align: center;}
</style>
Authors: WhoAmI, CrazyMonkey
email: kccddb@gmail.com
Date: 20230513
Copyright: CC BY-NC-SA

e.g.,
---
mkfifo fifo0
mkfifo fifo1
---
terminal 0:
./poll fifo0 fifo1
terminal 1:
echo "termainal 0" > fifo0
echo "termainal 1" > fifo1
**poll:**
On success, poll() returns a nonnegative value which is **the number of elements in the pollfds whose revents fields have been set to a nonzero value (indicating an event or an error).**
A return value of zero indicates that the system call timed out before any file descriptors became read.
On error, -1 is returned, and errno is set to indicate the error.
:::success
如果 您需要處理
Level-triggered and edge-triggered
或 超過 1024 的 connections
您需要用 Linux 特有的
[epoll ](https://man7.org/linux/man-pages/man7/epoll.7.html)
[epoll_wait](https://man7.org/linux/man-pages/man2/epoll_wait.2.html)
**thread 中使用 要特別小心 lock/unlock 的問題!!!**
[Using epoll() For Asynchronous Network Programming](https://kovyrin.net/2006/04/13/epoll-asynchronous-network-programming/)
epoll, epoll_ctl 使用 red-black tree
HW:
[epoll() Tutorial – epoll() In 3 Easy Steps!](https://www.suchprogramming.com/epoll-in-3-easy-steps/)
:::
<h1>
poll
</h1>
poll.c
```c=
/*
*
* Based on linux man page: poll_input.c
*
Licensed under GNU General Public License v2 or later.
#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
timeout: milliseconds
*/
#include <poll.h>
#include <fcntl.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
} while (0)
//timout=-1 : infinite timeout
#define timeout 10
#define buffersize 255
int
main(int argc, char *argv[])
{
int nfds, num_open_fds;
struct pollfd *pfds;
if (argc < 2) {
fprintf(stderr, "Usage: %s file...\n", argv[0]);
exit(EXIT_FAILURE);
}
num_open_fds = nfds = argc - 1;
pfds = calloc(nfds, sizeof(struct pollfd));
if (pfds == NULL)
errExit("malloc");
/* Open each file on command line, and add it 'pfds' array. */
for (int j = 0; j < nfds; j++) {
pfds[j].fd = open(argv[j + 1], O_RDONLY);
if (pfds[j].fd == -1)
errExit("open");
printf("Opened \"%s\" on fd %d\n", argv[j + 1], pfds[j].fd);
pfds[j].events = POLLIN;
}
/* Keep calling poll() as long as at least one file descriptor is
open. */
while (num_open_fds > 0) {
int ready;
printf("About to poll()\n");
//timout=-1 : infinite timeout
ready = poll(pfds, nfds, timeout);
if (ready == -1)
errExit("poll");
printf("Ready: %d\n", ready);
/* Deal with array returned by poll(). */
for (int j = 0; j < nfds; j++) {
char buf[buffersize+1];
if (pfds[j].revents != 0) {
printf(" fd=%d; events: %s%s%s\n", pfds[j].fd,
(pfds[j].revents & POLLIN) ? "POLLIN " : "",
(pfds[j].revents & POLLHUP) ? "POLLHUP " : "",
(pfds[j].revents & POLLERR) ? "POLLERR " : "");
if (pfds[j].revents & POLLIN) {
ssize_t s = read(pfds[j].fd, buf, sizeof(buf)-1);
if (s == -1)
errExit("read");
buf[s]=0;
// size_t or ssize_t argument
printf(" read %zd bytes: %s\n", s, buf);
} else { /* POLLERR | POLLHUP */
printf(" closing fd %d\n", pfds[j].fd);
if (close(pfds[j].fd) == -1)
errExit("close");
num_open_fds--;
}
}
}
}
free(pfds);
printf("All file descriptors closed; bye\n");
exit(EXIT_SUCCESS);
}
```
---
<h1>epoll</h1>
[epoll - I/O event notification facility](https://man7.org/linux/man-pages/man7/epoll.7.html)
[epoll_create, epoll_create1 - open an epoll file descriptor](https://man7.org/linux/man-pages/man2/epoll_create.2.html)
[epoll_ctl - control interface for an epoll file descriptor](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html)
[epoll_wait](https://man7.org/linux/man-pages/man2/epoll_wait.2.html)
#include <sys/epoll.h>
int epoll_wait(int epfd, struct epoll_event *events,
int maxevents, int timeout);
```c=
typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
struct epoll_event {
uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
```
The timeout argument specifies the number of <span class="red">milliseconds </span>that epoll_wait() will block.
Specifying a timeout of -1 causes epoll_wait() to block indefinitely, while specifying a timeout equal to zero cause epoll_wait() to return immediately, even if no events are available.
Maxevents is just the length of the struct epoll_events array pointed to by *events
**epoll.c**
```c=
/* Author: WhoAmI
* email: kccddb@gmail.com
* Licience: GPLv2
* File: epoll.c
* /
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#define BUFFERLEN 1024
#define perror(msg) do { perror(msg); exit(EXIT_FAILURE); \
} while (0)
#define pinfo(msg) do { fprintf(stdout,"%s",msg); } while (0)
#define MAX_EVENTS 20
int main(int argc, char *argv[]) {
const int EVENTS_SIZE = 20;
struct epoll_event ev, epev, events[MAX_EVENTS];
char echo[]="Good!!!!";
char buff[BUFFERLEN];
int socketFd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in sockAddr, cli_addr;
sockAddr.sin_port = htons(8088);
sockAddr.sin_family = AF_INET;
sockAddr.sin_addr.s_addr = htons(INADDR_ANY);
if (bind(socketFd, (struct sockaddr *) &sockAddr, sizeof(struct sockaddr)) == -1) {
printf( "bind error\n");
return -1;
}
if (listen(socketFd, 10) == -1) {
perror( "listen error");
return -1;
}
int eFd = epoll_create(1);
epev.events = EPOLLIN;
epev.data.fd = socketFd;
epoll_ctl(eFd, EPOLL_CTL_ADD, socketFd, &epev);
while (!0) {
int eNum = epoll_wait(eFd, events, EVENTS_SIZE, -1);
if (eNum == -1) {
perror( "epoll_wait " );
return -1;
}
for (int i = 0; i < eNum; i++) {
if (events[i].data.fd == socketFd) {
if (events[i].events & EPOLLIN) {
socklen_t length = sizeof(struct sockaddr);
int fd = accept(socketFd, (struct sockaddr *) &cli_addr, &length);
if (fd > 0) {
epev.events = EPOLLIN | EPOLLET;
epev.data.fd = fd;
int flags = fcntl(fd, F_GETFL, 0);
if (flags < 0) {
printf ("set no block error, fd: %d\n",fd);
continue;
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
printf("set no block error, fd:" , fd);
continue;
}
//add new connection
epoll_ctl(eFd, EPOLL_CTL_ADD, fd, &epev);
printf( "client on line fd: %d", fd);
}
}
} else {
/*
*
POLLRDHUP (since Linux 2.6.17)
Stream socket peer closed connection, or shut down writing
half of connection. The _GNU_SOURCE feature test macro
must be defined (before including any header files) in
order to obtain this definition.
*
POLLERR
Error condition (only returned in revents; ignored in
events). This bit is also set for a file descriptor
referring to the write end of a pipe when the read end has
been closed.
*
*/
if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP) {
//remove client fd
epoll_ctl(eFd, EPOLL_CTL_DEL, events[i].data.fd, events);
printf( "client out fd: %d\n" ,events[i].data.fd );;
close(events[i].data.fd);
} else if (events[i].events & EPOLLIN) {
int len = read(events[i].data.fd, buff, sizeof(buff)-1);
if (len == -1) {
epoll_ctl(eFd, EPOLL_CTL_DEL, events[i].data.fd, events);
printf("client out fd: %d\n",events[i].data.fd );
close(events[i].data.fd);
} else {
buff[len]=0;
printf("%s\n",buff);
write(events[i].data.fd, echo, sizeof(echo));
}
}
}
}
}
exit(EXIT_SUCCESS);
}
```
```c=
int exec(char *cmd)
{
FILE *fp;
char buffer[256];
fp = popen(cmd, "r");
while(fp){
fgets(buffer, sizeof(buffer), fp);
if(!feof(fp)){
printf(">");
printf("%s", buffer);
}
else{
pclose(fp);
return 0;
}
}
pclose(fp);
return 0;
}
```
**將上面兩段程式結合, 可以 telnet 至 server 執行 命令**