From: Jaroslav Kysela Date: Tue, 9 Apr 2013 12:31:20 +0000 (+0200) Subject: pcm: direct plugins: do more safe IPC semaphore handling X-Git-Tag: v1.0.27~4 X-Git-Url: https://git.alsa-project.org/?a=commitdiff_plain;h=a6813c2d0e2fa4586122d23748033a8bab206b8b;p=alsa-lib.git pcm: direct plugins: do more safe IPC semaphore handling As reported dead-lock, do local lock counting and invoke abort() when the lock counts do not match at close() time. Reported-by: Signed-off-by: Jaroslav Kysela --- diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h index 1c35dcb3..70c2c6a0 100644 --- a/src/pcm/pcm_direct.h +++ b/src/pcm/pcm_direct.h @@ -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); diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c index 16dba14b..2bd5d398 100644 --- a/src/pcm/pcm_dmix.c +++ b/src/pcm/pcm_dmix.c @@ -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); diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c index 1bdb670b..5b329510 100644 --- a/src/pcm/pcm_dshare.c +++ b/src/pcm/pcm_dshare.c @@ -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); diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c index ea07e041..055e4f49 100644 --- a/src/pcm/pcm_dsnoop.c +++ b/src/pcm/pcm_dsnoop.c @@ -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);