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: <mateen abdulmateen.shaikh@gmail.com>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
Jaroslav Kysela 2013-04-09 14:31:20 +02:00
parent b6eb0f9bfd
commit a6813c2d0e
4 changed files with 28 additions and 12 deletions

View 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);

View 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);

View 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);

View 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);