Files
asterisk/main/sem.c
David M. Lee e88afe2022 Taskprocessor optimization; switch Stasis to use taskprocessors
This patch optimizes taskprocessor to use a semaphore for signaling,
which the OS can do a better job at managing contention and waiting
that we can with a mutex and condition.

The taskprocessor execution was also slightly optimized to reduce the
number of locks taken.

The only observable difference in the taskprocessor implementation is
that when the final reference to the taskprocessor goes away, it will
execute all tasks to completion instead of discarding the unexecuted
tasks.

For systems where unnamed semaphores are not supported, a really
simple semaphore implementation is provided. (Which gives identical
performance as the original taskprocessor implementation).

The way we ended up implementing Stasis caused the threadpool to be a
burden instead of a boost to performance. This was switched to just
use taskprocessors directly for subscriptions.

Review: https://reviewboard.asterisk.org/r/2881/


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/12@400178 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-09-30 18:26:27 +00:00

117 lines
2.1 KiB
C

/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2013, Digium, Inc.
*
* David M. Lee, II <dlee@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*! \file
*
* \brief Asterisk semaphore support.
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/sem.h"
#include "asterisk/utils.h"
#ifndef HAS_WORKING_SEMAPHORE
/* DIY semaphores! */
int ast_sem_init(struct ast_sem *sem, int pshared, unsigned int value)
{
if (pshared) {
/* Don't need it... yet */
errno = ENOSYS;
return -1;
}
/* Since value is unsigned, this will also catch attempts to init with
* a negative value */
if (value > AST_SEM_VALUE_MAX) {
errno = EINVAL;
return -1;
}
sem->count = value;
sem->waiters = 0;
ast_mutex_init(&sem->mutex);
ast_cond_init(&sem->cond, NULL);
return 0;
}
int ast_sem_destroy(struct ast_sem *sem)
{
ast_mutex_destroy(&sem->mutex);
ast_cond_destroy(&sem->cond);
return 0;
}
int ast_sem_post(struct ast_sem *sem)
{
SCOPED_MUTEX(lock, &sem->mutex);
ast_assert(sem->count >= 0);
if (sem->count == AST_SEM_VALUE_MAX) {
errno = EOVERFLOW;
return -1;
}
/* Give it up! */
++sem->count;
/* Release a waiter, if needed */
if (sem->waiters) {
ast_cond_signal(&sem->cond);
}
return 0;
}
int ast_sem_wait(struct ast_sem *sem)
{
SCOPED_MUTEX(lock, &sem->mutex);
ast_assert(sem->count >= 0);
/* Wait for a non-zero count */
++sem->waiters;
while (sem->count == 0) {
ast_cond_wait(&sem->cond, &sem->mutex);
}
--sem->waiters;
/* Take it! */
--sem->count;
return 0;
}
int ast_sem_getvalue(struct ast_sem *sem, int *sval)
{
SCOPED_MUTEX(lock, &sem->mutex);
ast_assert(sem->count >= 0);
*sval = sem->count;
return 0;
}
#endif