/*
This is a simple "eventfd" example that uses io_uring
It demonstrates that reads work as expected on eventfds.
It uses liburing for simplicity.
*/


#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#include <fcntl.h>
#include <liburing.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/eventfd.h>

struct io_uring ring;


int main(int argc,  char * argv[]) {
      int fd = eventfd(0, 0);
      if(fd < 0) {
            printf("Could not open event fd.\n");
            return 2;
      }

      /* prep the array */
	char buf[sizeof(uint64_t)] = { 0 };
      struct iovec iov = { buf, 8 };

	{
            /* Do one write so we can compare blocking behaviour */
		eventfd_t val;
		val = 1;
		eventfd_write( fd, val );
	}

      /* init liburing */
      io_uring_queue_init(256, &ring, 0);

      /* declare required structs */
      struct io_uring_sqe * sqe;
      struct io_uring_cqe * cqe;

      /* get an sqe and fill in a READ operation */
      sqe = io_uring_get_sqe(&ring);
	io_uring_prep_read(sqe, fd, buf, 8, 0);

      sqe->user_data = fd;

      /* tell the kernel we have an sqe ready for consumption */
      io_uring_submit(&ring);

	printf("First wait\n");

      /* wait for the sqe to complete */
      int ret = io_uring_wait_cqe(&ring, &cqe);

      /* read and process cqe event */
      if(ret == 0) {
            signed int len = cqe->res;
            io_uring_cqe_seen(&ring, cqe);
		printf("%d ", len);
            if(len > 0) {
                  printf("%.*s", len, buf);
            }
            else if( len < 0 ) {
                  fprintf(stderr, "readv/read returned error : %s\n", strerror(-len));
            }
      }
      else {
            printf("%d\n", ret);
            io_uring_cqe_seen(&ring, cqe);
      }

      /* ============================================ */
      /* DO it again so the we can compare behaviour. */
      /* ============================================ */

      /* get an sqe and fill in a READ operation */
      sqe = io_uring_get_sqe(&ring);
	io_uring_prep_read(sqe, fd, buf, 8, 0);

      sqe->user_data = fd;

	printf("Second wait\n");

      /* tell the kernel we have an sqe ready for consumption */
      io_uring_submit(&ring);

      /* wait for the sqe to complete */
      ret = io_uring_wait_cqe(&ring, &cqe);

      /* read and process cqe event */
      if(ret == 0) {
            signed int len = cqe->res;
            io_uring_cqe_seen(&ring, cqe);
		printf("%d ", len);
            if(len > 0) {
                  printf("%.*s", len, buf);
            }
            else if( len < 0 ) {
                  fprintf(stderr, "readv/read returned error : %s\n", strerror(-len));
            }
      }
      else {
            printf("%d\n", ret);
            io_uring_cqe_seen(&ring, cqe);
      }

      io_uring_queue_exit(&ring);

      close(fd);
}