vss: Mmap audio files using MAP_POPULATE.
[paraslash.git] / vss.c
diff --git a/vss.c b/vss.c
index b9afc8ed637374c82918f3448695a1a2fdaa94a2..e833543e785788876af91d691b73cf8876899de3 100644 (file)
--- a/vss.c
+++ b/vss.c
@@ -952,6 +952,10 @@ static int recv_afs_msg(int afs_socket, int *fd, uint32_t *code, uint32_t *data)
        return 1;
 }
 
        return 1;
 }
 
+#ifndef MAP_POPULATE
+#define MAP_POPULATE 0
+#endif
+
 static void recv_afs_result(struct vss_task *vsst, fd_set *rfds)
 {
        int ret, passed_fd, shmid;
 static void recv_afs_result(struct vss_task *vsst, fd_set *rfds)
 {
        int ret, passed_fd, shmid;
@@ -986,8 +990,8 @@ static void recv_afs_result(struct vss_task *vsst, fd_set *rfds)
        }
        mmd->size = statbuf.st_size;
        mmd->mtime = statbuf.st_mtime;
        }
        mmd->size = statbuf.st_size;
        mmd->mtime = statbuf.st_mtime;
-       ret = para_mmap(mmd->size, PROT_READ, MAP_PRIVATE, passed_fd,
-               0, &vsst->map);
+       ret = para_mmap(mmd->size, PROT_READ, MAP_PRIVATE | MAP_POPULATE,
+               passed_fd, 0, &vsst->map);
        if (ret < 0)
                goto err;
        close(passed_fd);
        if (ret < 0)
                goto err;
        close(passed_fd);
@@ -1076,6 +1080,23 @@ static void vss_send(struct vss_task *vsst)
                }
                mmd->chunks_sent++;
                mmd->current_chunk++;
                }
                mmd->chunks_sent++;
                mmd->current_chunk++;
+               /*
+                * Prefault next chunk(s)
+                *
+                * If the backing device of the memory-mapped audio file is
+                * slow and read-ahead is turned off or prevented for some
+                * reason, e.g. due to memory pressure, it may take much longer
+                * than the chunk interval to get the next chunk on the wire,
+                * causing buffer underruns on the client side. Mapping the
+                * file with MAP_POPULATE seems to help a bit, but it does not
+                * eliminate the delays completely. Moreover, it is supported
+                * only on Linux. So we do our own read-ahead here.
+                */
+               buf += len;
+               for (i = 0; i < 5 && buf < vsst->map + mmd->size; i++) {
+                       __a_unused volatile char x = *buf;
+                       buf += 4096;
+               }
        }
 }
 
        }
 }