ソースを参照

faster & simpler solution for stream poll() - release

Philippe G 4 年 前
コミット
6c184efa92
1 ファイル変更20 行追加31 行削除
  1. 20 31
      components/squeezelite/stream.c

+ 20 - 31
components/squeezelite/stream.c

@@ -46,27 +46,17 @@ struct buffer *streambuf = &buf;
 #define UNLOCK   mutex_unlock(streambuf->mutex)
 
 /* 
-After a lot of hesitation, I've added that "poll mutex" to prevent
-socket from being allocated while we are still in poll(). The issue 
-happens is we have a close quickly followed by an open, we might still
-be in the poll() and simple OS fail as they re-allocate the same socket
-on which a thread is still waiting. 
-Ideally, you want to set the lock in the disconnect() but that would mean
-very often we'd have to always wait for the end of the poll(), i.e. up to
-100ms for nothing most of the time where if it is in the open(), it is 
-less elegant as closing a socket on which there is a poll() is not good 
-but it's more efficient as it is very rare that you'd have an open() less 
-then 100ms after a close()
+When LMS sends a close/open sequence very quickly, the stream thread might
+still be waiting in the poll() on the closed socket. It is never recommended
+to have a thread closing a socket used by another thread but it works, as
+opposed to an infinite select(). 
+In stream_sock() a new socket is created and full OS will allocate a different
+one but on RTOS and simple IP stack, the same might be re-used and that causes
+an exception as a thread is already waiting on a newly allocated socket
+A simple variable that forces stream_sock() to wait until we are out of poll()
+is enough and much faster than a mutex 
 */
-#if EMBEDDED
-static mutex_type poll_mutex;
-#define LOCK_L   mutex_lock(poll_mutex)
-#define UNLOCK_L mutex_unlock(poll_mutex)
-#else
-#define LOCK_L   
-#define UNLOCK_L 
-#endif
-
+static bool polling;
 static sockfd fd;
 
 struct streamstate stream;
@@ -209,7 +199,7 @@ static void *stream_thread() {
 
 		} else {
 
-			LOCK_L;
+			polling = true;
 			pollinfo.fd = fd;
 			pollinfo.events = POLLIN;
 			if (stream.state == SEND_HEADERS) {
@@ -221,7 +211,7 @@ static void *stream_thread() {
 		
 		if (_poll(ssl, &pollinfo, 100)) {
 
-			UNLOCK_L;	
+			polling = false;
 			LOCK;
 
 			// check socket has not been closed while in poll
@@ -374,7 +364,8 @@ static void *stream_thread() {
 			UNLOCK;
 			
 		} else {
-			UNLOCK_L;
+			// it is safe to set it unlocked
+			polling = false;
 			LOG_SDEBUG("poll timeout");
 		}
 	}
@@ -427,9 +418,6 @@ void stream_init(log_level level, unsigned stream_buf_size) {
 	*stream.header = '\0';
 
 	fd = -1;
-#if EMBEDDED	
-	mutex_create_p(poll_mutex);
-#endif	
 
 #if LINUX || FREEBSD
 	touch_memory(streambuf->buf, streambuf->size);
@@ -459,9 +447,6 @@ void stream_close(void) {
 #endif
 	free(stream.header);
 	buf_destroy(streambuf);
-#if EMBEDDED	
-	mutex_destroy(poll_mutex);
-#endif	
 }
 
 void stream_file(const char *header, size_t header_len, unsigned threshold) {
@@ -503,9 +488,13 @@ void stream_file(const char *header, size_t header_len, unsigned threshold) {
 void stream_sock(u32_t ip, u16_t port, const char *header, size_t header_len, unsigned threshold, bool cont_wait) {
 	struct sockaddr_in addr;
 
-	LOCK_L;
+#if EMBEDDED
+	// wait till we are not polling anymore
+	for (LOCK; running && polling; UNLOCK, usleep(10000), LOCK);
+	UNLOCK;
+#endif	
+	
 	int sock = socket(AF_INET, SOCK_STREAM, 0);
-	UNLOCK_L;
 
 	if (sock < 0) {
 		LOG_ERROR("failed to create socket");