Package: dvbstream
Version: 0.5-2

Whilst looking at a kernel memory leak, I found out that dvbstream is
calling poll() ~ 1500 times a second on my machine.

I've attached a patch which replaces poll() with select().  This also
leads to a 15% reduction in CPU usage in my testing.

Adrian
-- 
Email: [EMAIL PROTECTED]  -*-  GPG key available on public key servers
Debian GNU/Linux - the maintainable distribution   -*-  www.debian.org
Avoid working with children, animals and Microsoft "operating" systems
diff -Naur dvbstream-0.5-orig/CHANGES dvbstream-0.5/CHANGES
--- dvbstream-0.5-orig/CHANGES  2002-05-15 17:39:58.000000000 +0100
+++ dvbstream-0.5/CHANGES       2006-04-01 00:02:05.000000000 +0100
@@ -1,3 +1,14 @@
+v0.5.1 - 31st March 2006:
+-------------------------
+Changed by Adrian Bridgett from poll() to select().
+Saves ~1500 accept() calls/second which translates into approx 15% CPU saving. 
+
+
+v0.5 - ??
+---------
+Unknown
+
+
 V0.4 - 29th October 2001:
 -------------------------
 
diff -Naur dvbstream-0.5-orig/dvbstream.c dvbstream-0.5/dvbstream.c
--- dvbstream-0.5-orig/dvbstream.c      2004-02-11 15:34:21.000000000 +0000
+++ dvbstream-0.5/dvbstream.c   2006-03-31 23:55:47.000000000 +0100
@@ -30,7 +30,7 @@
 #include <ctype.h>
 #include <sys/ioctl.h>
 #include <sys/time.h>
-#include <sys/poll.h>
+#include <sys/select.h>
 #include <sys/stat.h>
 #include <resolv.h>
 #include <fcntl.h>
@@ -174,22 +174,10 @@
   }
 }
 
-void make_nonblock(int f) {
-  int oldflags;
-
-  if ((oldflags=fcntl(f,F_GETFL,0)) < 0) {
-    perror("F_GETFL");
-  }
-  oldflags|=O_NONBLOCK;
-  if (fcntl(f,F_SETFL,oldflags) < 0) {
-    perror("F_SETFL");
-  }
-}
-
 typedef enum {STREAM_ON,STREAM_OFF} state_t;
 
 
-  int socketIn, ns;
+  int socketIn, ns = -1;
   int pids[MAX_CHANNELS];
   int pestypes[MAX_CHANNELS];
   unsigned char hi_mappids[8192];
@@ -197,7 +185,6 @@
   int fd_sec;
   int fd_frontend;
   int pid,pid2;
-  int connectionOpen;
   int fromlen;
   char hostname[64];
   char in_ch;
@@ -220,33 +207,31 @@
 #define TS_SIZE 188
 #define IN_SIZE TS_SIZE
 
+int accept_telnet() {
+  /* Open a new telnet session if a client is trying to connect */
+  if ((ns = accept(socketIn, (struct sockaddr *)&fsin, &fromlen)) < 0) {
+    perror ("server: accept");
+    return -1;
+  }
+
+  printf("Opened connection\n");
+  writes(ns,"220-DVBSTREAM - ");
+  writes(ns,hostname);
+  writes(ns,"\r\nDONE\r\n");
+  return 1;
+}
+
 int process_telnet() {
-  char cmd[1024];
-  int cmd_i=0;
+  static char cmd[1024] = "\0";
+  static int cmd_i=0;
   int i;
   char* ch;
   dmx_pes_type_t pestype;
   unsigned long freq=0;
   unsigned long srate=0;
 
-    /* Open a new telnet session if a client is trying to connect */
-    if (ns==-1) {
-      if ((ns = accept(socketIn, (struct sockaddr *)&fsin, &fromlen)) > 0) {
-        make_nonblock(ns);
-        cmd_i=0;      
-        cmd[0]=0;
-        printf("Opened connection\n");
-        writes(ns,"220-DVBSTREAM - ");
-        writes(ns,hostname);
-        writes(ns,"\r\nDONE\r\n");
-        connectionOpen=1;
-      }
-    }
-
-    /* If a telnet session is open, receive and process any input */
-    if (connectionOpen) {
       /* Read in at most a line of text - any ctrl character ends the line */
-      while (read(ns,&in_ch,1)>0) {
+      while (recv(ns,&in_ch,1,MSG_DONTWAIT)>0) {
           if (in_ch < 32) break;
           /* Prevent buffer overflows */
           if (cmd_i < 1024-1) {
@@ -261,7 +246,6 @@
             writes(ns,"DONE\r\n");
             close(ns);
             ns=-1;
-            connectionOpen=0; 
             printf("Closed connection\n");
           } else if (strcasecmp(cmd,"STOP")==0) {
             writes(ns,"STOP\n");
@@ -352,7 +336,6 @@
           writes(ns,"DONE\r\n");
         }
       }
-    }
     return(0);
 }
 
@@ -444,7 +427,8 @@
   int fd_dvr;
   int i,j;
   unsigned char buf[MTU];
-  struct pollfd pfds[2];  // DVR device and Telnet connection
+  fd_set select_fds;      // DVR device, telnet socket and connection
+  int num_fds;
   unsigned int secs = 0;
   unsigned long freq=0;
   unsigned long srate=0;
@@ -691,7 +675,6 @@
              f = fopen(pids_map[map_cnt-1].filename, "w+b");
              if (f != NULL) {
                pids_map[map_cnt-1].fd = fileno(f);
-               make_nonblock(pids_map[map_cnt-1].fd);
                fprintf(stderr, "Open file %s\n", pids_map[map_cnt-1].filename);
              } else {
                pids_map[map_cnt-1].fd = -1;
@@ -729,7 +712,7 @@
 
   if ((output_type==RTP_PS) && (npids!=2)) {
     fprintf(stderr,"ERROR: PS requires exactly two PIDS - video and audio.\n");
-    exit;
+    exit(1);
   }
 
   if (signal(SIGHUP, SignalHandler) == SIG_IGN) signal(SIGHUP, SIG_IGN);
@@ -823,32 +806,53 @@
     exit(1);
   }
 
-  make_nonblock(socketIn);
-
   if (listen(socketIn, 1) < 0) {
     perror("server: listen");
     exit(1);
   }
 
-  connectionOpen=0;
-  ns=-1;
-  pfds[0].fd=fd_dvr;
-  pfds[0].events=POLLIN|POLLPRI;
-  pfds[1].events=POLLIN|POLLPRI;
-
   /* Set up timer */
   //  if (secs > 0) alarm(secs);
   while ( !Interrupted) {
-    /* Poll the open file descriptors */
-    if (ns==-1) {
-        poll(pfds,1,500);
+    // setup select descriptor set
+    // we always wait on DVR device and
+    // either the socket or telnet session
+    // only one session at a time ATM
+    // in fact, process_telnet can only handle one session
+    FD_ZERO(&select_fds);
+    FD_SET(fd_dvr,&select_fds);
+    if (ns == -1) {
+      FD_SET(socketIn,&select_fds);
     } else {
-        pfds[1].fd=ns;  // This can change
-        poll(pfds,2,500);
+      FD_SET(ns,&select_fds);
+    }
+    
+    num_fds = (socketIn >= ns) ? socketIn : ns;
+    num_fds++;
+    if (select(num_fds, &select_fds, NULL, NULL, NULL) < 0) {
+      if (errno == EINTR) {
+       continue;
+      }
+      perror("server: select");
+      exit(1);
+    }
+    
+    if (FD_ISSET(socketIn, &select_fds)) {
+      if (ns != -1) {
+       fprintf(stderr,"Multiple telnets not supported");
+      } else {
+        accept_telnet();
+      }
     }
 
-    process_telnet();  // See if there is an incoming telnet connection
+    if ((ns != -1) && FD_ISSET(ns, &select_fds)) {
+      process_telnet();
+    }
 
+    if (! FD_ISSET(fd_dvr, &select_fds)) {
+      continue;
+    }
+           
     if (output_type==RTP_TS) {
       /* Attempt to read 188 bytes from /dev/ost/dvr */
       if ((bytes_read = read(fd_dvr,free_bytes,PACKET_SIZE)) > 0) {

Reply via email to