]> git.alsa-project.org Git - alsa-lib.git/commitdiff
pcm: direct plugins: do more safe IPC semaphore handling
authorJaroslav Kysela <perex@perex.cz>
Tue, 9 Apr 2013 12:31:20 +0000 (14:31 +0200)
committerJaroslav Kysela <perex@perex.cz>
Tue, 9 Apr 2013 12:37:21 +0000 (14:37 +0200)
As reported dead-lock, do local lock counting and invoke abort() when
the lock counts do not match at close() time.

Reported-by: <mateen abdulmateen.shaikh@gmail.com>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
src/pcm/pcm_direct.h
src/pcm/pcm_dmix.c
src/pcm/pcm_dshare.c
src/pcm/pcm_dsnoop.c

index 1c35dcb3d75ce104b90d42e00a917bb7a5d6526d..70c2c6a0229fc9dae6512034e1559d3c9d3dc5f4 100644 (file)
@@ -122,6 +122,7 @@ struct snd_pcm_direct {
        mode_t ipc_perm;                /* IPC socket permissions */
        int ipc_gid;                    /* IPC socket gid */
        int semid;                      /* IPC global semaphore identification */
+       int locked[DIRECT_IPC_SEMS];    /* local lock counter */
        int shmid;                      /* IPC global shared memory identification */
        snd_pcm_direct_share_t *shmptr; /* pointer to shared memory area */
        snd_pcm_t *spcm;                /* slave PCM handle */
@@ -257,13 +258,26 @@ static inline int snd_pcm_direct_semaphore_discard(snd_pcm_direct_t *dmix)
 static inline int snd_pcm_direct_semaphore_down(snd_pcm_direct_t *dmix, int sem_num)
 {
        struct sembuf op[2] = { { sem_num, 0, 0 }, { sem_num, 1, SEM_UNDO } };
-       return semop(dmix->semid, op, 2);
+       int err = semop(dmix->semid, op, 2);
+       if (err == 0) dmix->locked[sem_num]++;
+       return err;
 }
 
 static inline int snd_pcm_direct_semaphore_up(snd_pcm_direct_t *dmix, int sem_num)
 {
        struct sembuf op = { sem_num, -1, SEM_UNDO | IPC_NOWAIT };
-       return semop(dmix->semid, &op, 1);
+       int err = semop(dmix->semid, &op, 1);
+       if (err == 0) dmix->locked[sem_num]--;
+       return err;
+}
+
+static inline int snd_pcm_direct_semaphore_final(snd_pcm_direct_t *dmix, int sem_num)
+{
+       if (dmix->locked[sem_num] != 1) {
+               assert(dmix->locked[sem_num] != 1);
+               abort();
+       }
+       return snd_pcm_direct_semaphore_up(dmix, sem_num);
 }
 
 int snd_pcm_direct_shm_create_or_connect(snd_pcm_direct_t *dmix);
index 16dba14bc531165eecd3ca10c7baf5af359c06b1..2bd5d398d280c07eaf54d99afb053c3be29f602d 100644 (file)
@@ -781,9 +781,9 @@ static int snd_pcm_dmix_close(snd_pcm_t *pcm)
        shm_sum_discard(dmix);
        if (snd_pcm_direct_shm_discard(dmix)) {
                if (snd_pcm_direct_semaphore_discard(dmix))
-                       snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
+                       snd_pcm_direct_semaphore_final(dmix, DIRECT_IPC_SEM_CLIENT);
        } else
-               snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
+               snd_pcm_direct_semaphore_final(dmix, DIRECT_IPC_SEM_CLIENT);
        free(dmix->bindings);
        pcm->private_data = NULL;
        free(dmix);
index 1bdb670b874cb870902e1d9555bd63ce9b95230b..5b329510481e2165361165124ddbf2fc9c2af3f8 100644 (file)
@@ -470,10 +470,11 @@ static int snd_pcm_dshare_close(snd_pcm_t *pcm)
                snd_pcm_direct_server_discard(dshare);
        if (dshare->client)
                snd_pcm_direct_client_discard(dshare);
-       if (snd_pcm_direct_shm_discard(dshare))
-               snd_pcm_direct_semaphore_discard(dshare);
-       else
-               snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT);
+       if (snd_pcm_direct_shm_discard(dshare)) {
+               if (snd_pcm_direct_semaphore_discard(dshare))
+                       snd_pcm_direct_semaphore_final(dshare, DIRECT_IPC_SEM_CLIENT);
+       } else
+               snd_pcm_direct_semaphore_final(dshare, DIRECT_IPC_SEM_CLIENT);
        free(dshare->bindings);
        pcm->private_data = NULL;
        free(dshare);
index ea07e041c5bc719a465514b40038e3a0443a14a9..055e4f4983432cdfe7e3d6f10a8dfa5612952560 100644 (file)
@@ -391,10 +391,11 @@ static int snd_pcm_dsnoop_close(snd_pcm_t *pcm)
                snd_pcm_direct_server_discard(dsnoop);
        if (dsnoop->client)
                snd_pcm_direct_client_discard(dsnoop);
-       if (snd_pcm_direct_shm_discard(dsnoop))
-               snd_pcm_direct_semaphore_discard(dsnoop);
-       else
-               snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT);
+       if (snd_pcm_direct_shm_discard(dsnoop)) {
+               if (snd_pcm_direct_semaphore_discard(dsnoop))
+                       snd_pcm_direct_semaphore_final(dsnoop, DIRECT_IPC_SEM_CLIENT);
+       } else
+               snd_pcm_direct_semaphore_final(dsnoop, DIRECT_IPC_SEM_CLIENT);
        free(dsnoop->bindings);
        pcm->private_data = NULL;
        free(dsnoop);