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
------------------------------------------------------------------------
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) {