source: example/io/simple/server_epoll.c @ 4db0140

Last change on this file since 4db0140 was ccb8c8a, checked in by Thierry Delisle <tdelisle@…>, 4 years ago

fix epoll server.
Needed to use EPOLLOUT | EPOLLIN rather than just EPOLLIN.
No clue what IN vs OUT means for rings in io_uring.

  • Property mode set to 100644
File size: 4.9 KB
Line 
1/*
2Similar to the server in servier.c, this is a simple server
3that instead uses epoll to block.
4It opens the door to have several polling user-thread per cluster.
5It uses liburing for simplicity.
6*/
7
8
9#include <assert.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13
14#include <unistd.h>
15
16#include <sys/epoll.h>
17#include <sys/types.h>
18#include <sys/socket.h>
19#include <netinet/in.h>
20
21#include <liburing.h>
22
23#define MAX_EVENTS 10
24struct epoll_event ev, events[MAX_EVENTS];
25
26struct io_uring ring;
27
28char data[256];
29struct iovec iov = { data, 256 };
30struct msghdr msg = { (void *)"", 0, &iov, 1, NULL, 0, 0 };
31static void async_read(int sock) {
32        /* get an sqe and fill in a READ operation */
33      struct io_uring_sqe * sqe = io_uring_get_sqe(&ring);
34      io_uring_prep_recvmsg(sqe, sock, &msg, 0);
35      sqe->user_data = 0;
36
37      /* tell the kernel we have an sqe ready for consumption */
38      int ret = io_uring_submit(&ring);
39      assert(ret == 1);
40}
41
42int main(int argc, char *argv[]) {
43        if(argc != 2) {
44            printf("usage:    %s portnumber\n", argv[0]);
45            exit( EXIT_FAILURE );
46      }
47      int port = atoi(argv[1]);
48      if(port < 1) {
49            printf("Invalid port : %d (from %s)\n", port, argv[1]);
50            exit( EXIT_FAILURE );
51      }
52
53        int sock = socket(AF_INET, SOCK_STREAM, 0);
54        if(sock < 0) {
55                perror( "socket" );
56                exit( EXIT_FAILURE );
57        }
58
59        struct sockaddr_in serv_addr;
60      memset(&serv_addr, 0, sizeof(serv_addr));
61      serv_addr.sin_family = AF_INET;
62      serv_addr.sin_addr.s_addr = INADDR_ANY;
63      serv_addr.sin_port = htons(port);
64
65        int ret = bind(sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
66        if(ret < 0) {
67                perror( "bind" );
68                exit( EXIT_FAILURE );
69        }
70
71
72        listen(sock,1);
73
74        struct sockaddr_in cli_addr;
75        __socklen_t clilen = sizeof(cli_addr);
76        int newsock = accept(sock, (struct sockaddr *) &cli_addr, &clilen);
77        if (newsock < 0) {
78                perror( "accept" );
79                exit( EXIT_FAILURE );
80        }
81
82        io_uring_queue_init( 16, &ring, 0 );
83
84      int epollfd = epoll_create1(0);
85      if (epollfd == -1) {
86            perror("epoll_create1");
87            exit(EXIT_FAILURE);
88      }
89
90      ev.events = EPOLLOUT | EPOLLIN | EPOLLONESHOT;
91      ev.data.u64 = (uint64_t)&ring;
92      if (epoll_ctl(epollfd, EPOLL_CTL_ADD, ring.ring_fd, &ev) == -1) {
93            perror("epoll_ctl: first");
94            exit(EXIT_FAILURE);
95      }
96
97
98        async_read( newsock );
99
100        while(1) {
101            BLOCK:;
102            int nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
103            if (nfds == -1) {
104                  perror("epoll_wait");
105                  exit(EXIT_FAILURE);
106            }
107
108
109                while(1) {
110                  struct io_uring_cqe * cqe;
111                  int ret = io_uring_peek_cqe( &ring, &cqe );
112
113                  if( ret < 0 ) {
114                        if(-ret == EAGAIN) {
115                              if (epoll_ctl(epollfd, EPOLL_CTL_MOD, ring.ring_fd, &ev) == -1) {
116                                    perror("epoll_ctl: loop");
117                                    exit(EXIT_FAILURE);
118                              }
119                              goto BLOCK;
120                        }
121                        printf( "Main Loop Error : %s\n", strerror(-ret) );
122                        close( sock );
123                        exit( EXIT_FAILURE );
124                  }
125
126                  switch(cqe->user_data) {
127                        // Read completed
128                        case 0:
129                              // If it is the end of file we are done
130                              if( cqe->res == 0 ) {
131                                    goto END;
132                              }
133
134                              if( cqe->res < 0 ) {
135                                    perror( "Main Loop Error" );
136                                    close( sock );
137                                    exit( EXIT_FAILURE );
138                              }
139
140                              printf("'%.*s'\n", cqe->res, data);
141
142                              async_read( newsock );
143
144                              // otherwise prepare a new read
145                              break;
146                        // Wait timed out, time to print
147                        // Requires Linux 5.4
148                        case LIBURING_UDATA_TIMEOUT:
149                              printf(".");
150                              break;
151                        // Problem
152                        default:
153                              printf("Unexpected user data : %llu", cqe->user_data);
154                              exit( EXIT_FAILURE );
155                  }
156
157                  io_uring_cqe_seen( &ring, cqe );
158            }
159        }
160END:
161
162        io_uring_queue_exit( &ring );
163
164        ret = close(newsock);
165      if(ret < 0) {
166            perror( "close new" );
167            exit( EXIT_FAILURE );
168      }
169
170        ret = close(sock);
171      if(ret < 0) {
172            perror( "close old" );
173            exit( EXIT_FAILURE );
174      }
175
176        return 0;
177}
Note: See TracBrowser for help on using the repository browser.