changeset 24131:30028bbcb9e8

Use a single select() for both key and slave input Previous code used two separate select() calls one after another, so that whenever it was running select() on one set of fds events in the other set would go unnoticed until later. Now there's a single select() which allows reacting immediately to any input source. The behavior of the new code differs somewhat from the old; for example multiple fds that stay readable are no longer handled in a round-robin fashion and the total amount the process sleeps can differ. Some tuning might be required later.
author uau
date Sat, 25 Aug 2007 04:28:11 +0000
parents d62ddc94c474
children 9f234010c4be
files input/input.c
diffstat 1 files changed, 120 insertions(+), 198 deletions(-) [+]
line wrap: on
line diff
--- a/input/input.c	Sat Aug 25 04:28:09 2007 +0000
+++ b/input/input.c	Sat Aug 25 04:28:11 2007 +0000
@@ -991,126 +991,25 @@
   return ret;
 }
 
-int
-mp_input_read_key_code(int time) {
-#ifdef HAVE_POSIX_SELECT
-  fd_set fds;
-  struct timeval tv,*time_val;
-#endif
-  int i,n=0,max_fd = 0, did_sleep = 0;
-  static int last_loop = 0;
-
-  if(num_key_fd == 0)
-  {
-    if (time)
-      usec_sleep(time * 1000);
-    return MP_INPUT_NOTHING;
-  }
-
-#ifdef HAVE_POSIX_SELECT
-  FD_ZERO(&fds);
-#endif
-  // Remove fd marked as dead and build the fd_set
-  // n == number of fd's to be select() checked
-  for(i = 0; (unsigned int)i < num_key_fd; i++) {
-    if (key_fds[i].dead) {
-      mp_input_rm_key_fd(key_fds[i].fd);
-      i--;
-      continue;
-    } else if (key_fds[i].no_select)
-      continue;
-    if(key_fds[i].fd > max_fd)
-      max_fd = key_fds[i].fd;
-#ifdef HAVE_POSIX_SELECT
-    FD_SET(key_fds[i].fd,&fds);
-#endif
-    n++;
-  }
-
-#ifdef HAVE_POSIX_SELECT
-// if we have fd's without MP_FD_NO_SELECT flag, call select():
-if(n>0){
-
-  if(time >= 0 ) {
-    tv.tv_sec=time/1000; 
-    tv.tv_usec = (time%1000)*1000;
-    time_val = &tv;
-  } else
-    time_val = NULL;
-  
-  while(1) {
-    if(select(max_fd+1,&fds,NULL,NULL,time_val) < 0) {
-      if(errno == EINTR)
-	continue;
-      mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrSelect,strerror(errno));
-    }
-    break;
-  }
-  did_sleep = 1;
-
-}
-#endif
-
-  for(i = last_loop + 1 ; i != last_loop ; i++) {
-    int code = -1;
-    // This is to check all fds in turn
-    if((unsigned int)i >= num_key_fd) {
-      i = -1;
-      last_loop++;
-      last_loop %= (num_key_fd+1);
-      continue;
-    }
-#ifdef HAVE_POSIX_SELECT
-    // No input from this fd
-    if (!key_fds[i].no_select && !FD_ISSET(key_fds[i].fd, &fds))
-      continue;
-#endif
-    if(key_fds[i].fd == 0) { // stdin is handled by getch2
-      getch2();
-      code = mplayer_get_key(0);
-      if(code < 0)
-	code = MP_INPUT_NOTHING;
-    }
-    else
-      code = ((mp_key_func_t)key_fds[i].read_func)(key_fds[i].fd);
-
-    if(code >= 0)
-      return code;
-
-    if(code == MP_INPUT_ERROR)
-      mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrOnKeyInFd,key_fds[i].fd);
-    else if(code == MP_INPUT_DEAD) {
-      mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrDeadKeyOnFd,key_fds[i].fd);
-      key_fds[i].dead = 1;
-    }
-  }
-  if (time && !did_sleep)
-    usec_sleep(time * 1000);
-  return MP_INPUT_NOTHING;
-}
-    
 
 static mp_cmd_t*
-mp_input_read_keys(int time,int paused) {
-  int code = mp_input_read_key_code(time);
+interpret_key(int code, int paused)
+{
   unsigned int j;
   mp_cmd_t* ret;
 
   if(mp_input_key_cb) {
-    for( ; code >= 0 ;   code = mp_input_read_key_code(0) ) {
-      if(code & MP_KEY_DOWN) continue;
+      if (code & MP_KEY_DOWN)
+	  return NULL;
       code &= ~(MP_KEY_DOWN|MP_NO_REPEAT_KEY);
       mp_input_key_cb(code);
-    }
     return NULL;
   }
 
-  for( ; code >= 0 ;   code = mp_input_read_key_code(0) ) {
-    // key pushed
     if(code & MP_KEY_DOWN) {
       if(num_key_down > MP_MAX_KEY_DOWN) {
 	mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_Err2ManyKeyDowns);
-	continue;
+	return NULL;
       }
       code &= ~MP_KEY_DOWN;
       // Check if we don't already have this key as pushed
@@ -1119,12 +1018,12 @@
 	  break;
       }
       if(j != num_key_down)
-	continue; 
+	return NULL;
       key_down[num_key_down] = code;
       num_key_down++;
       last_key_down = GetTimer();
       ar_state = 0;
-      continue;
+      return NULL;
     }
     // key released
     // Check if the key is in the down key, driver which can't send push event
@@ -1136,7 +1035,7 @@
     if(j == num_key_down) { // key was not in the down keys : add it
       if(num_key_down > MP_MAX_KEY_DOWN) {
 	mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_Err2ManyKeyDowns);
-	continue;
+	return NULL;
       }
       key_down[num_key_down] = code;
       num_key_down++;
@@ -1154,10 +1053,11 @@
       mp_cmd_free(ar_cmd);
       ar_cmd = NULL;
     }
-    if(ret)
-      return ret;
-  }
+    return ret;
+}
 
+static mp_cmd_t *check_autorepeat(int paused)
+{
   // No input : autorepeat ?
   if(ar_rate > 0 && ar_state >=0 && num_key_down > 0 && ! (key_down[num_key_down-1] & MP_NO_REPEAT_KEY)) {
     unsigned int t = GetTimer();
@@ -1177,103 +1077,127 @@
       return mp_cmd_clone(ar_cmd);
     }
   }
-
   return NULL;
 }
 
-static mp_cmd_t*
-mp_input_read_cmds(int time) {
-#ifdef HAVE_POSIX_SELECT
-  fd_set fds;
-  struct timeval tv,*time_val;
-#endif
-  int i,n = 0,max_fd = 0,got_cmd = 0;
-  mp_cmd_t* ret;
-  static int last_loop = 0;
 
-  if(num_cmd_fd == 0)
-    return NULL;
-
-#ifdef HAVE_POSIX_SELECT
-  FD_ZERO(&fds);
-#endif
-  for(i = 0; (unsigned int)i < num_cmd_fd ; i++) {
-    if (cmd_fds[i].dead || cmd_fds[i].eof) {
-      mp_input_rm_cmd_fd(cmd_fds[i].fd);
-      i--;
-      continue;
-    } else if (cmd_fds[i].no_select)
-      continue;
-    if (cmd_fds[i].got_cmd)
-      got_cmd = 1;
-    if(cmd_fds[i].fd > max_fd)
-      max_fd = cmd_fds[i].fd;
+static mp_cmd_t *read_events(int time, int paused)
+{
+    int i;
+    int got_cmd = 0;
+    for (i = 0; i < num_key_fd; i++)
+	if (key_fds[i].dead) {
+	    mp_input_rm_key_fd(key_fds[i].fd);
+	    i--;
+	}
+    for (i = 0; i < num_cmd_fd; i++)
+	if (cmd_fds[i].dead || cmd_fds[i].eof) {
+	    mp_input_rm_cmd_fd(cmd_fds[i].fd);
+	    i--;
+	}
+	else if (cmd_fds[i].got_cmd)
+	    got_cmd = 1;
 #ifdef HAVE_POSIX_SELECT
-    FD_SET(cmd_fds[i].fd,&fds);
-#endif
-    n++;
-  }
-
-  if(num_cmd_fd == 0)
-    return NULL;
-
-#ifdef HAVE_POSIX_SELECT
-  if(time >= 0) {
-    tv.tv_sec=time/1000; 
-    tv.tv_usec = (time%1000)*1000;
-    time_val = &tv;
-  } else
-    time_val = NULL;
-    
-  while(n > 0) {
-    if((i = select(max_fd+1,&fds,NULL,NULL,time_val)) <= 0) {
-      if(i < 0) {
-	if(errno == EINTR)
-	  continue;
-	mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrSelect,strerror(errno));
-      }
-      if(!got_cmd)
-	return NULL;
+    int max_fd = 0, num_fd = 0;
+    fd_set fds;
+    FD_ZERO(&fds);
+    if (!got_cmd) {
+	for (i = 0; i < num_key_fd; i++) {
+	    if (key_fds[i].no_select)
+		continue;
+	    if (key_fds[i].fd > max_fd)
+		max_fd = key_fds[i].fd;
+	    FD_SET(key_fds[i].fd, &fds);
+	    num_fd++;
+	}
+	for (i = 0; i < num_cmd_fd; i++) {
+	    if (cmd_fds[i].no_select)
+		continue;
+	    if (cmd_fds[i].fd > max_fd)
+		max_fd = cmd_fds[i].fd;
+	    FD_SET(cmd_fds[i].fd, &fds);
+	    num_fd++;
+	}
+	if (num_fd > 0) {
+	    struct timeval tv, *time_val;
+	    if (time >= 0) {
+		tv.tv_sec = time / 1000;
+		tv.tv_usec = (time % 1000) * 1000;
+		time_val = &tv;
+	    }
+	    else
+		time_val = NULL;
+	    if (select(max_fd + 1, &fds, NULL, NULL, time_val) < 0) {
+		if (errno != EINTR)
+		    mp_msg(MSGT_INPUT, MSGL_ERR, MSGTR_INPUT_INPUT_ErrSelect,
+			    strerror(errno));
+		FD_ZERO(&fds);
+	    }
+	}
     }
-    break;
-  }
+#else
+    if (!got_cmd)
+	usec_sleep(time * 1000);
 #endif
 
-  for(i = last_loop + 1; i !=  last_loop ; i++) {
-    int r = 0;
-    char* cmd;
-    if((unsigned int)i >= num_cmd_fd) {
-      i = -1;
-      last_loop++;
-      last_loop %= (num_cmd_fd+1);
-      continue;
-    }
+
+    for (i = 0; i < num_key_fd; i++) {
 #ifdef HAVE_POSIX_SELECT
-    if (!cmd_fds[i].no_select && ! FD_ISSET(cmd_fds[i].fd, &fds)
-        && !cmd_fds[i].got_cmd)
-      continue;
+	if (!key_fds[i].no_select && !FD_ISSET(key_fds[i].fd, &fds))
+	    continue;
 #endif
 
-    r = mp_input_read_cmd(&cmd_fds[i],&cmd);
-    if(r < 0) {
-      if(r == MP_INPUT_ERROR)
-	mp_msg(MSGT_INPUT,MSGL_ERR,MSGTR_INPUT_INPUT_ErrOnCmdFd,cmd_fds[i].fd);
-      else if(r == MP_INPUT_DEAD)
-	cmd_fds[i].dead = 1;
-      continue;
+	int code;
+	if (key_fds[i].fd == 0) {   // getch2 handler special-cased for now
+	    getch2();
+	    code = mplayer_get_key(0);
+	    if (code < 0)
+		code = MP_INPUT_NOTHING;
+	}
+	else
+	    code = ((mp_key_func_t)key_fds[i].read_func)(key_fds[i].fd);
+	if (code >= 0) {
+	    mp_cmd_t *ret = interpret_key(code, paused);
+	    if (ret)
+		return ret;
+	}
+	else if (code == MP_INPUT_ERROR)
+	    mp_msg(MSGT_INPUT, MSGL_ERR, MSGTR_INPUT_INPUT_ErrOnKeyInFd,
+		   key_fds[i].fd);
+	else if (code == MP_INPUT_DEAD) {
+	    mp_msg(MSGT_INPUT, MSGL_ERR, MSGTR_INPUT_INPUT_ErrDeadKeyOnFd,
+		   key_fds[i].fd);
+	    key_fds[i].dead = 1;
+	}
     }
-    ret = mp_input_parse_cmd(cmd);
-    free(cmd);
-    if(!ret)
-      continue;
-    last_loop = i;
-    return ret;
-  }
-  
-  last_loop = 0;
-  return NULL;  
+    mp_cmd_t *autorepeat_cmd = check_autorepeat(paused);
+    if (autorepeat_cmd)
+	return autorepeat_cmd;
+
+    for (i = 0; i < num_cmd_fd; i++) {
+#ifdef HAVE_POSIX_SELECT
+	if (!cmd_fds[i].no_select && !FD_ISSET(cmd_fds[i].fd, &fds))
+	    continue;
+#endif
+	char *cmd;
+	int r = mp_input_read_cmd(&cmd_fds[i], &cmd);
+	if (r >= 0) {
+	    mp_cmd_t *ret = mp_input_parse_cmd(cmd);
+	    free(cmd);
+	    if (ret)
+		return ret;
+	}
+	else if (r == MP_INPUT_ERROR)
+	    mp_msg(MSGT_INPUT, MSGL_ERR, MSGTR_INPUT_INPUT_ErrOnCmdFd,
+		   cmd_fds[i].fd);
+	else if (r == MP_INPUT_DEAD)
+	    cmd_fds[i].dead = 1;
+    }
+
+    return NULL;
 }
 
+
 int
 mp_input_queue_cmd(mp_cmd_t* cmd) {
   if(cmd_queue_length  >= CMD_QUEUE_SIZE)
@@ -1316,9 +1240,7 @@
     ret = mp_input_get_queued_cmd(peek_only);
     if(ret) break;
     from_queue = 0;
-    ret = mp_input_read_keys(time,paused);
-    if(ret) break;
-    ret = mp_input_read_cmds(time);
+    ret = read_events(time, paused);
     break;
   }
   if(!ret) return NULL;