Re-use fds array; fix for sel_fd in use PAZ-947
[pazpar2-moved-to-github.git] / src / eventl.c
index 9804472..87bcecd 100644 (file)
@@ -1,5 +1,5 @@
 /* This file is part of Pazpar2.
- Copyright (C) 2006-2011 Index Data
+ Copyright (C) Index Data
 
  Pazpar2 is free software; you can redistribute it and/or modify it under
  the terms of the GNU General Public License as published by the Free
@@ -20,7 +20,7 @@
 /*
  * Based on  ParaZ - a simple tool for harvesting performance data for
  * parallel operations using Z39.50.
- * Copyright (C) 2006-2011 Index Data ApS
+ * Copyright (C) Index Data ApS
  * See LICENSE file for details.
  */
 
@@ -104,6 +104,8 @@ struct iochan_man_s {
     int no_threads;
     int log_level;
     YAZ_MUTEX iochan_mutex;
+    int size_fds;
+    struct yaz_poll_fd *fds;
 };
 
 iochan_man_t iochan_man_create(int no_threads) {
@@ -114,6 +116,8 @@ iochan_man_t iochan_man_create(int no_threads) {
     man->no_threads = no_threads;
     man->log_level = yaz_log_module_level("iochan");
     man->iochan_mutex = 0;
+    man->size_fds = 0;
+    man->fds = 0;
     yaz_mutex_create(&man->iochan_mutex);
     return man;
 }
@@ -142,6 +146,7 @@ void iochan_man_destroy(iochan_man_t *mp) {
             c = iochan_destroy_real(c);
         }
         yaz_mutex_destroy(&(*mp)->iochan_mutex);
+        xfree((*mp)->fds);
         xfree(*mp);
         *mp = 0;
     }
@@ -195,16 +200,14 @@ static void work_handler(void *work_data) {
 }
 
 static void run_fun(iochan_man_t man, IOCHAN p) {
-    if (p->this_event) {
-        if (man->sel_thread) {
-            yaz_log(man->log_level,
-                    "eventl: work add chan=%p name=%s event=%d", p,
-                    p->name ? p->name : "", p->this_event);
-            p->thread_users++;
-            sel_thread_add(man->sel_thread, p);
-        } else
-            work_handler(p);
-    }
+    if (man->sel_thread) {
+        yaz_log(man->log_level,
+                "eventl: work add chan=%p name=%s event=%d", p,
+                p->name ? p->name : "", p->this_event);
+        p->thread_users++;
+        sel_thread_add(man->sel_thread, p);
+    } else
+        work_handler(p);
 }
 
 static int event_loop(iochan_man_t man, IOCHAN *iochans) {
@@ -213,17 +216,11 @@ static int event_loop(iochan_man_t man, IOCHAN *iochans) {
         IOCHAN p, *nextp;
         IOCHAN start;
         IOCHAN inv_start;
-        fd_set in, out, except;
-        int res, max;
+        int res;
         static struct timeval to;
-        struct timeval *timeout;
-
-//        struct yaz_poll_fd *fds;
-        int no_fds = 0;
-        FD_ZERO(&in);
-        FD_ZERO(&out);
-        FD_ZERO(&except);
-        timeout = &to; /* hang on select */
+        struct yaz_poll_fd *fds;
+        int i, no_fds = 0;
+        int connection_fired = 0;
         to.tv_sec = 300;
         to.tv_usec = 0;
 
@@ -233,48 +230,60 @@ static int event_loop(iochan_man_t man, IOCHAN *iochans) {
         start = man->channel_list;
         yaz_mutex_leave(man->iochan_mutex);
         inv_start = start;
-        for (p = start; p; p = p->next) {
+        for (p = start; p; p = p->next)
+            if (p->fd >= 0)
+                no_fds++;
+        if (man->sel_fd != -1)
             no_fds++;
+        if (no_fds > man->size_fds)
+        {
+            man->size_fds = no_fds * 2;
+            man->fds = xrealloc(man->fds, man->size_fds * sizeof(*man->fds));
         }
-//        fds = (struct yaz_poll_fd *) xmalloc(no_fds * sizeof(*fds));
-
-        max = 0;
-        for (p = start; p; p = p->next) {
+        fds = man->fds;
+        i = 0;
+        if (man->sel_fd != -1)
+        {
+            fds[i].fd = man->sel_fd;
+            fds[i].input_mask = yaz_poll_read;
+            i++;
+        }
+        for (p = start; p; p = p->next)
+        {
             if (p->thread_users > 0)
                 continue;
             if (p->max_idle && p->max_idle < to.tv_sec)
                 to.tv_sec = p->max_idle;
             if (p->fd < 0)
                 continue;
+            fds[i].fd = p->fd;
+            fds[i].input_mask = 0;
             if (p->flags & EVENT_INPUT)
-                FD_SET(p->fd, &in);
+                fds[i].input_mask |= yaz_poll_read;
             if (p->flags & EVENT_OUTPUT)
-                FD_SET(p->fd, &out);
+                fds[i].input_mask |= yaz_poll_write;
             if (p->flags & EVENT_EXCEPT)
-                FD_SET(p->fd, &except);
-            if (p->fd > max)
-                max = p->fd;
-        }
-        yaz_log(man->log_level, "max=%d sel_fd=%d", max, man->sel_fd);
-
-        if (man->sel_fd != -1) {
-            if (man->sel_fd > max)
-                max = man->sel_fd;
-            FD_SET(man->sel_fd, &in);
+                fds[i].input_mask |= yaz_poll_except;
+            i++;
         }
-        yaz_log(man->log_level, "select begin nofds=%d", max);
-        res = select(max + 1, &in, &out, &except, timeout);
-        yaz_log(man->log_level, "select returned res=%d", res);
-        if (res < 0) {
+        yaz_log(man->log_level, "yaz_poll begin nofds=%d", no_fds);
+        res = yaz_poll(fds, no_fds, to.tv_sec, 0);
+        yaz_log(man->log_level, "yaz_poll returned res=%d", res);
+        if (res < 0)
+        {
             if (errno == EINTR)
                 continue;
             else {
-                yaz_log(YLOG_ERRNO | YLOG_WARN, "select");
+                yaz_log(YLOG_ERRNO | YLOG_WARN, "poll");
                 return 0;
             }
         }
-        if (man->sel_fd != -1) {
-            if (FD_ISSET(man->sel_fd, &in)) {
+        i = 0;
+        if (man->sel_fd != -1)
+        {
+            assert(fds[i].fd == man->sel_fd);
+            if (fds[i].output_mask)
+            {
                 IOCHAN chan;
 
                 yaz_log(man->log_level, "eventl: sel input on sel_fd=%d",
@@ -286,51 +295,79 @@ static int event_loop(iochan_man_t man, IOCHAN *iochans) {
                     chan->thread_users--;
                 }
             }
+            i++;
         }
-        if (man->log_level) {
+        if (man->log_level)
+        {
             int no = 0;
-            for (p = start; p; p = p->next) {
+            for (p = start; p; p = p->next)
                 no++;
-            }
             yaz_log(man->log_level, "%d channels", no);
         }
-        for (p = start; p; p = p->next) {
+        for (p = start; p; p = p->next)
+        {
             time_t now = time(0);
 
-            if (p->destroyed) {
+            if (p->destroyed)
+            {
                 yaz_log(man->log_level,
                         "eventl: skip destroyed chan=%p name=%s", p,
                         p->name ? p->name : "");
+                if (p->fd >= 0)
+                    i++;
                 continue;
             }
-            if (p->thread_users > 0) {
+            if (p->thread_users > 0)
+            {
                 yaz_log(man->log_level,
                         "eventl: skip chan=%p name=%s users=%d", p,
                         p->name ? p->name : "", p->thread_users);
+                if (p->fd >= 0)
+                    i++;
                 continue;
             }
             p->this_event = 0;
 
-            if (p->max_idle && now - p->last_event > p->max_idle) {
+            if (p->max_idle && now - p->last_event > p->max_idle)
+            {
                 p->last_event = now;
                 p->this_event |= EVENT_TIMEOUT;
             }
-            if (p->fd >= 0) {
-                if (FD_ISSET(p->fd, &in)) {
+            if (p->fd >= 0)
+            {
+                assert(fds[i].fd == p->fd);
+                if (fds[i].output_mask & yaz_poll_read)
+                {
                     p->last_event = now;
                     p->this_event |= EVENT_INPUT;
                 }
-                if (FD_ISSET(p->fd, &out)) {
+                if (fds[i].output_mask & yaz_poll_write)
+                {
                     p->last_event = now;
                     p->this_event |= EVENT_OUTPUT;
                 }
-                if (FD_ISSET(p->fd, &except)) {
+                if (fds[i].output_mask & yaz_poll_except)
+                {
                     p->last_event = now;
                     p->this_event |= EVENT_EXCEPT;
                 }
+                i++;
+            }
+            /* only fire one Z39.50/SRU socket event.. except for timeout */
+            if (p->this_event) {
+                if (!(p->this_event & EVENT_TIMEOUT) &&
+                    !strcmp(p->name, "connection_socket"))
+                {
+                    /* not a timeout and we have a Z39.50/SRU socket */
+                    if (connection_fired == 0)
+                        run_fun(man, p);
+                    connection_fired++;
+                }
+                else
+                    run_fun(man, p);
             }
-            run_fun(man, p);
         }
+
         assert(inv_start == start);
         yaz_mutex_enter(man->iochan_mutex);
         for (nextp = iochans; *nextp;) {