Newer
Older
lline_buffer_size += CB_INCR + siz + 1;
}
strcat(lline_buffer,str);
}
static void CB_RESET(void )
{
comment_buffer[0] = 0;
/*! \brief Keep track of how many threads are currently trying to wait*() on
* a child process */
static unsigned int safe_system_level = 0;
static struct sigaction safe_system_prev_handler;
/*! \brief NULL handler so we can collect the child exit status */
static void _null_sig_handler(int sig)
}
static struct sigaction null_sig_handler = {
.sa_handler = _null_sig_handler,
void ast_replace_sigchld(void);
void ast_replace_sigchld(void)
{
level = safe_system_level++;
/* only replace the handler if it has not already been done */
if (level == 0) {
sigaction(SIGCHLD, &null_sig_handler, &safe_system_prev_handler);
}
}
void ast_unreplace_sigchld(void)
{
unsigned int level;
/* only restore the handler if we are the last one */
if (level == 0) {
sigaction(SIGCHLD, &safe_system_prev_handler, NULL);
}
}
int ast_safe_system(const char *s);
int ast_safe_system(const char *s)
{
pid_t pid;
#ifdef HAVE_WORKING_FORK
int x;
#endif
int res;
#if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
ast_replace_sigchld();
#else
if (pid == 0) {
#ifdef HAVE_WORKING_FORK
/* Close file descriptors and launch system command */
for (x = STDERR_FILENO + 1; x < 4096; x++)
close(x);
#endif
execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
_exit(1);
} else if (pid > 0) {
for(;;) {
res = waitpid(pid, &status, 0);
if (res > -1) {
res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
break;
} else if (errno != EINTR)
}
} else {
ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
res = -1;
}
ast_unreplace_sigchld();
#else
res = -1;
#endif
return res;
}
static struct ast_comment *ALLOC_COMMENT(const char *buffer)
struct ast_comment *x = ast_calloc(1,sizeof(struct ast_comment)+strlen(buffer)+1);
strcpy(x->cmt, buffer);
return x;
}
static struct ast_config_map {
struct ast_config_map *next;
char *name;
char *driver;
char *database;
char *table;
char stuff[0];
} *config_maps = NULL;
static struct ast_config_engine *config_engine_list;
struct ast_category {
char name[80];
int ignored; /*!< do not let user of the config see this category */
char *file; /*!< the file name from whence this declaration was read */
int lineno;
struct ast_comment *precomments;
struct ast_comment *sameline;
struct ast_variable *root;
struct ast_variable *last;
struct ast_category *next;
};
struct ast_config {
struct ast_category *root;
struct ast_category *last;
struct ast_category *current;
struct ast_category *last_browse; /*!< used to cache the last category supplied via category_browse */
int include_level;
int max_include_level;
struct ast_config_include *includes; /*!< a list of inclusions, which should describe the entire tree */
};
struct ast_config_include {
char *include_location_file; /*!< file name in which the include occurs */
int include_location_lineno; /*!< lineno where include occurred */
int exec; /*!< set to non-zero if itsa #exec statement */
char *exec_file; /*!< if it's an exec, you'll have both the /var/tmp to read, and the original script */
char *included_file; /*!< file name included */
int inclusion_count; /*!< if the file is included more than once, a running count thereof -- but, worry not,
we explode the instances and will include those-- so all entries will be unique */
int output; /*!< a flag to indicate if the inclusion has been output */
struct ast_config_include *next; /*!< ptr to next inclusion in the list */
};
typedef struct ast_config *config_load_func(const char *database, const char *table, const char *configfile, struct ast_config *config, int withcomments, const char *suggested_include_file);
typedef struct ast_variable *realtime_var_get(const char *database, const char *table, va_list ap);
typedef struct ast_config *realtime_multi_get(const char *database, const char *table, va_list ap);
typedef int realtime_update(const char *database, const char *table, const char *keyfield, const char *entity, va_list ap);
/*! \brief Configuration engine structure, used to define realtime drivers */
struct ast_config_engine {
char *name;
config_load_func *load_func;
realtime_var_get *realtime_func;
realtime_multi_get *realtime_multi_func;
realtime_update *update_func;
struct ast_config_engine *next;
};
static struct ast_config_engine *config_engine_list;
static force_inline int ast_strlen_zero(const char *s)
{
}
#define S_OR(a, b) (!ast_strlen_zero(a) ? (a) : (b))
AST_INLINE_API(
void ast_copy_string(char *dst, const char *src, size_t size),
{
while (*src && size) {
*dst++ = *src++;
size--;
}
if (__builtin_expect(!size, 0))
dst--;
*dst = '\0';
}
AST_INLINE_API(
char *ast_skip_blanks(const char *str),
{
while (*str && *str < 33)
str++;
return (char *)str;
}
/*!
\brief Trims trailing whitespace characters from a string.
\param ast_trim_blanks function being used
\param str the input string
\return a pointer to the modified string
*/
AST_INLINE_API(
char *ast_trim_blanks(char *str),
{
/* It's tempting to only want to erase after we exit this loop,
but since ast_trim_blanks *could* receive a constant string
(which we presumably wouldn't have to touch), we shouldn't
actually set anything unless we must, and it's easier just
to set each position to \0 than to keep track of a variable
for it */
while ((work >= str) && *work < 33)
*(work--) = '\0';
}
}
/*!
\brief Strip leading/trailing whitespace from a string.
\param s The string to be stripped (will be modified).
\return The stripped string.
This functions strips all leading and trailing whitespace
characters from the input string, and returns a pointer to
the resulting string. The string is modified in place.
*/
AST_INLINE_API(
char *ast_strip(char *s),
{
s = ast_skip_blanks(s);
if (s)
ast_trim_blanks(s);
return s;
struct ast_variable {
char *name;
char *value;
char *file;
int lineno;
int object; /*!< 0 for variable, 1 for object */
int blanklines; /*!< Number of blanklines following entry */
struct ast_comment *precomments;
struct ast_comment *sameline;
struct ast_variable *next;
char stuff[0];
};
static const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable);
static struct ast_config *config_text_file_load(const char *database, const char *table, const char *filename, struct ast_config *cfg, int withcomments, const char *suggested_include_file);
struct ast_config *localized_config_load_with_comments(const char *filename);
static char *ast_category_browse(struct ast_config *config, const char *prev);
static struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category);
static void ast_variables_destroy(struct ast_variable *v);
static void ast_config_destroy(struct ast_config *cfg);
static struct ast_config_include *ast_include_new(struct ast_config *conf, const char *from_file, const char *included_file, int is_exec, const char *exec_file, int from_lineno, char *real_included_file_name, int real_included_file_name_size);
static struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file);
void localized_ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file);
static struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename);
static struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename)
{
int name_len = strlen(name) + 1;
if ((variable = ast_calloc(1, name_len + strlen(value) + 1 + strlen(filename) + 1 + sizeof(*variable)))) {
variable->name = variable->stuff;
variable->value = variable->stuff + name_len;
variable->file = variable->value + strlen(value) + 1;
strcpy(variable->name,name);
strcpy(variable->value,value);
strcpy(variable->file,filename);
}
}
static struct ast_config_include *ast_include_new(struct ast_config *conf, const char *from_file, const char *included_file, int is_exec, const char *exec_file, int from_lineno, char *real_included_file_name, int real_included_file_name_size)
{
/* a file should be included ONCE. Otherwise, if one of the instances is changed,
then all be changed. -- how do we know to include it? -- Handling modified
instances is possible, I'd have
to create a new master for each instance. */
struct ast_config_include *inc;
inc = ast_include_find(conf, included_file);
if (inc)
{
inc->inclusion_count++;
snprintf(real_included_file_name, real_included_file_name_size, "%s~~%d", included_file, inc->inclusion_count);
ast_log(LOG_WARNING,"'%s', line %d: Same File included more than once! This data will be saved in %s if saved back to disk.\n", from_file, from_lineno, real_included_file_name);
} else
*real_included_file_name = 0;
inc = ast_calloc(1,sizeof(struct ast_config_include));
inc->include_location_file = ast_strdup(from_file);
inc->include_location_lineno = from_lineno;
if (!ast_strlen_zero(real_included_file_name))
inc->included_file = ast_strdup(real_included_file_name);
else
inc->included_file = ast_strdup(included_file);
inc->exec = is_exec;
if (is_exec)
inc->exec_file = ast_strdup(exec_file);
/* attach this new struct to the conf struct */
inc->next = conf->includes;
conf->includes = inc;
}
void localized_ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file)
{
struct ast_config_include *incl;
struct ast_category *cat;
struct ast_variable *v;
int from_len = strlen(from_file);
int to_len = strlen(to_file);
if (strcmp(from_file, to_file) == 0) /* no use wasting time if the name is the same */
return;
/* the manager code allows you to read in one config file, then
write it back out under a different name. But, the new arrangement
ties output lines to the file name. So, before you try to write
the config file to disk, better riffle thru the data and make sure
the file names are changed.
*/
/* file names are on categories, includes (of course), and on variables. So,
traverse all this and swap names */
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
for (incl = conf->includes; incl; incl=incl->next) {
if (strcmp(incl->include_location_file,from_file) == 0) {
if (from_len >= to_len)
strcpy(incl->include_location_file, to_file);
else {
free(incl->include_location_file);
incl->include_location_file = strdup(to_file);
}
}
}
for (cat = conf->root; cat; cat = cat->next) {
if (strcmp(cat->file,from_file) == 0) {
if (from_len >= to_len)
strcpy(cat->file, to_file);
else {
free(cat->file);
cat->file = strdup(to_file);
}
}
for (v = cat->root; v; v = v->next) {
if (strcmp(v->file,from_file) == 0) {
if (from_len >= to_len)
strcpy(v->file, to_file);
else {
free(v->file);
v->file = strdup(to_file);
}
}
}
}
}
static struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file)
{
struct ast_config_include *x;
for (x=conf->includes;x;x=x->next)
{
if (strcmp(x->included_file,included_file) == 0)
return x;
}
return 0;
}
static void ast_variable_append(struct ast_category *category, struct ast_variable *variable);
static void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
{
if (!variable)
return;
if (category->last)
category->last->next = variable;
else
category->root = variable;
category->last = variable;
while (category->last->next)
category->last = category->last->next;
}
static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored);
static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored)
{
/* try exact match first, then case-insensitive match */
for (cat = config->root; cat; cat = cat->next) {
if (cat->name == category_name && (ignored || !cat->ignored))
return cat;
}
for (cat = config->root; cat; cat = cat->next) {
if (!strcasecmp(cat->name, category_name) && (ignored || !cat->ignored))
return cat;
}
return NULL;
}
static struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name)
{
}
static struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category)
{
if (category && config->last_browse && (config->last_browse->name == category))
cat = config->last_browse;
else
cat = ast_category_get(config, category);
}
static const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
{
if (category) {
for (v = ast_variable_browse(config, category); v; v = v->next) {
if (!strcasecmp(variable, v->name))
return v->value;
}
} else {
struct ast_category *cat;
for (cat = config->root; cat; cat = cat->next)
for (v = cat->root; v; v = v->next)
if (!strcasecmp(variable, v->name))
return v->value;
}
}
static struct ast_variable *variable_clone(const struct ast_variable *old)
{
struct ast_variable *new = ast_variable_new(old->name, old->value, old->file);
if (new) {
new->lineno = old->lineno;
new->object = old->object;
new->blanklines = old->blanklines;
/* TODO: clone comments? */
}
}
static void ast_variables_destroy(struct ast_variable *v)
{
while (v) {
vn = v;
v = v->next;
free(vn);
}
}
static void ast_includes_destroy(struct ast_config_include *incls)
{
for (incl=incls; incl; incl = inclnext) {
inclnext = incl->next;
if (incl->include_location_file)
free(incl->include_location_file);
if (incl->exec_file)
free(incl->exec_file);
if (incl->included_file)
free(incl->included_file);
free(incl);
}
}
static void ast_config_destroy(struct ast_config *cfg)
{
cat = cfg->root;
while (cat) {
ast_variables_destroy(cat->root);
catn = cat;
cat = cat->next;
free(catn);
}
free(cfg);
}
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
enum ast_option_flags {
/*! Allow \#exec in config files */
AST_OPT_FLAG_EXEC_INCLUDES = (1 << 0),
/*! Do not fork() */
AST_OPT_FLAG_NO_FORK = (1 << 1),
/*! Keep quiet */
AST_OPT_FLAG_QUIET = (1 << 2),
/*! Console mode */
AST_OPT_FLAG_CONSOLE = (1 << 3),
/*! Run in realtime Linux priority */
AST_OPT_FLAG_HIGH_PRIORITY = (1 << 4),
/*! Initialize keys for RSA authentication */
AST_OPT_FLAG_INIT_KEYS = (1 << 5),
/*! Remote console */
AST_OPT_FLAG_REMOTE = (1 << 6),
/*! Execute an asterisk CLI command upon startup */
AST_OPT_FLAG_EXEC = (1 << 7),
/*! Don't use termcap colors */
AST_OPT_FLAG_NO_COLOR = (1 << 8),
/*! Are we fully started yet? */
AST_OPT_FLAG_FULLY_BOOTED = (1 << 9),
/*! Trascode via signed linear */
AST_OPT_FLAG_TRANSCODE_VIA_SLIN = (1 << 10),
/*! Dump core on a seg fault */
AST_OPT_FLAG_DUMP_CORE = (1 << 12),
/*! Cache sound files */
AST_OPT_FLAG_CACHE_RECORD_FILES = (1 << 13),
/*! Display timestamp in CLI verbose output */
AST_OPT_FLAG_TIMESTAMP = (1 << 14),
/*! Override config */
AST_OPT_FLAG_OVERRIDE_CONFIG = (1 << 15),
/*! Reconnect */
AST_OPT_FLAG_RECONNECT = (1 << 16),
/*! Transmit Silence during Record() and DTMF Generation */
AST_OPT_FLAG_TRANSMIT_SILENCE = (1 << 17),
/*! Suppress some warnings */
AST_OPT_FLAG_DONT_WARN = (1 << 18),
/*! End CDRs before the 'h' extension */
AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN = (1 << 19),
/*! Always fork, even if verbose or debug settings are non-zero */
AST_OPT_FLAG_ALWAYS_FORK = (1 << 21),
/*! Disable log/verbose output to remote consoles */
AST_OPT_FLAG_MUTE = (1 << 22),
/*! There is a per-file debug setting */
AST_OPT_FLAG_DEBUG_FILE = (1 << 23),
/*! There is a per-file verbose setting */
AST_OPT_FLAG_VERBOSE_FILE = (1 << 24),
/*! Terminal colors should be adjusted for a light-colored background */
AST_OPT_FLAG_LIGHT_BACKGROUND = (1 << 25),
/*! Count Initiated seconds in CDR's */
AST_OPT_FLAG_INITIATED_SECONDS = (1 << 26),
/*! Force black background */
AST_OPT_FLAG_FORCE_BLACK_BACKGROUND = (1 << 27),
};
/* options.h declares ast_options extern; I need it static? */
#define AST_CACHE_DIR_LEN 512
#define AST_FILENAME_MAX 80
/*! These are the options that set by default when Asterisk starts */
#define AST_DEFAULT_OPTIONS AST_OPT_FLAG_TRANSCODE_VIA_SLIN
struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
#define ast_opt_exec_includes ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES)
#define ast_opt_no_fork ast_test_flag(&ast_options, AST_OPT_FLAG_NO_FORK)
#define ast_opt_quiet ast_test_flag(&ast_options, AST_OPT_FLAG_QUIET)
#define ast_opt_console ast_test_flag(&ast_options, AST_OPT_FLAG_CONSOLE)
#define ast_opt_high_priority ast_test_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY)
#define ast_opt_init_keys ast_test_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS)
#define ast_opt_remote ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)
#define ast_opt_exec ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC)
#define ast_opt_no_color ast_test_flag(&ast_options, AST_OPT_FLAG_NO_COLOR)
#define ast_fully_booted ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)
#define ast_opt_transcode_via_slin ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN)
#define ast_opt_priority_jumping ast_test_flag(&ast_options, AST_OPT_FLAG_PRIORITY_JUMPING)
#define ast_opt_dump_core ast_test_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE)
#define ast_opt_cache_record_files ast_test_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES)
#define ast_opt_timestamp ast_test_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP)
#define ast_opt_override_config ast_test_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG)
#define ast_opt_reconnect ast_test_flag(&ast_options, AST_OPT_FLAG_RECONNECT)
#define ast_opt_transmit_silence ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE)
#define ast_opt_dont_warn ast_test_flag(&ast_options, AST_OPT_FLAG_DONT_WARN)
#define ast_opt_end_cdr_before_h_exten ast_test_flag(&ast_options, AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN)
#define ast_opt_always_fork ast_test_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK)
#define ast_opt_mute ast_test_flag(&ast_options, AST_OPT_FLAG_MUTE)
extern int option_verbose;
extern int option_debug; /*!< Debugging */
extern int ast_option_maxcalls; /*!< Maximum number of simultaneous channels */
extern double ast_option_maxload;
extern char ast_defaultlanguage[];
extern char record_cache_dir[AST_CACHE_DIR_LEN];
extern char debug_filename[AST_FILENAME_MAX];
extern int ast_language_is_prefix;
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
/* linkedlists.h */
/*!
\brief Write locks a list.
\param head This is a pointer to the list head structure
This macro attempts to place an exclusive write lock in the
list head structure pointed to by head.
Returns non-zero on success, 0 on failure
*/
#define AST_RWLIST_WRLOCK(head) \
ast_rwlock_wrlock(&(head)->lock)
/*!
\brief Read locks a list.
\param head This is a pointer to the list head structure
This macro attempts to place a read lock in the
list head structure pointed to by head.
Returns non-zero on success, 0 on failure
*/
#define AST_RWLIST_RDLOCK(head) \
ast_rwlock_rdlock(&(head)->lock)
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
/*!
\brief Attempts to unlock a read/write based list.
\param head This is a pointer to the list head structure
This macro attempts to remove a read or write lock from the
list head structure pointed to by head. If the list
was not locked by this thread, this macro has no effect.
*/
#define AST_RWLIST_UNLOCK(head) \
ast_rwlock_unlock(&(head)->lock)
/*!
\brief Defines a structure to be used to hold a list of specified type.
\param name This will be the name of the defined structure.
\param type This is the type of each list entry.
This macro creates a structure definition that can be used
to hold a list of the entries of type \a type. It does not actually
declare (allocate) a structure; to do that, either follow this
macro with the desired name of the instance you wish to declare,
or use the specified \a name to declare instances elsewhere.
Example usage:
\code
static AST_LIST_HEAD(entry_list, entry) entries;
\endcode
This would define \c struct \c entry_list, and declare an instance of it named
\a entries, all intended to hold a list of type \c struct \c entry.
*/
#define AST_LIST_HEAD(name, type) \
struct name { \
struct type *first; \
struct type *last; \
ast_mutex_t lock; \
}
/*!
\brief Defines a structure to be used to hold a read/write list of specified type.
\param name This will be the name of the defined structure.
\param type This is the type of each list entry.
This macro creates a structure definition that can be used
to hold a list of the entries of type \a type. It does not actually
declare (allocate) a structure; to do that, either follow this
macro with the desired name of the instance you wish to declare,
or use the specified \a name to declare instances elsewhere.
Example usage:
\code
static AST_RWLIST_HEAD(entry_list, entry) entries;
\endcode
This would define \c struct \c entry_list, and declare an instance of it named
\a entries, all intended to hold a list of type \c struct \c entry.
*/
#define AST_RWLIST_HEAD(name, type) \
struct name { \
struct type *first; \
struct type *last; \
ast_rwlock_t lock; \
}
/*!
\brief Defines a structure to be used to hold a list of specified type (with no lock).
\param name This will be the name of the defined structure.
\param type This is the type of each list entry.
This macro creates a structure definition that can be used
to hold a list of the entries of type \a type. It does not actually
declare (allocate) a structure; to do that, either follow this
macro with the desired name of the instance you wish to declare,
or use the specified \a name to declare instances elsewhere.
Example usage:
\code
static AST_LIST_HEAD_NOLOCK(entry_list, entry) entries;
\endcode
This would define \c struct \c entry_list, and declare an instance of it named
\a entries, all intended to hold a list of type \c struct \c entry.
*/
#define AST_LIST_HEAD_NOLOCK(name, type) \
struct name { \
struct type *first; \
struct type *last; \
}
/*!
\brief Defines initial values for a declaration of AST_LIST_HEAD
*/
#define AST_LIST_HEAD_INIT_VALUE { \
.first = NULL, \
.last = NULL, \
.lock = AST_MUTEX_INIT_VALUE, \
}
/*!
\brief Defines initial values for a declaration of AST_RWLIST_HEAD
*/
#define AST_RWLIST_HEAD_INIT_VALUE { \
.first = NULL, \
.last = NULL, \
.lock = AST_RWLOCK_INIT_VALUE, \
}
/*!
\brief Defines initial values for a declaration of AST_LIST_HEAD_NOLOCK
*/
#define AST_LIST_HEAD_NOLOCK_INIT_VALUE { \
.first = NULL, \
.last = NULL, \
}
/*!
\brief Defines a structure to be used to hold a list of specified type, statically initialized.
\param name This will be the name of the defined structure.
\param type This is the type of each list entry.
This macro creates a structure definition that can be used
to hold a list of the entries of type \a type, and allocates an instance
of it, initialized to be empty.
Example usage:
\code
static AST_LIST_HEAD_STATIC(entry_list, entry);
\endcode
This would define \c struct \c entry_list, intended to hold a list of
type \c struct \c entry.
*/
#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
#define AST_LIST_HEAD_STATIC(name, type) \
struct name { \
struct type *first; \
struct type *last; \
ast_mutex_t lock; \
} name; \
static void __attribute__((constructor)) init_##name(void) \
{ \
AST_LIST_HEAD_INIT(&name); \
} \
static void __attribute__((destructor)) fini_##name(void) \
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
{ \
AST_LIST_HEAD_DESTROY(&name); \
} \
struct __dummy_##name
#else
#define AST_LIST_HEAD_STATIC(name, type) \
struct name { \
struct type *first; \
struct type *last; \
ast_mutex_t lock; \
} name = AST_LIST_HEAD_INIT_VALUE
#endif
/*!
\brief Defines a structure to be used to hold a read/write list of specified type, statically initialized.
\param name This will be the name of the defined structure.
\param type This is the type of each list entry.
This macro creates a structure definition that can be used
to hold a list of the entries of type \a type, and allocates an instance
of it, initialized to be empty.
Example usage:
\code
static AST_RWLIST_HEAD_STATIC(entry_list, entry);
\endcode
This would define \c struct \c entry_list, intended to hold a list of
type \c struct \c entry.
*/
#ifndef AST_RWLOCK_INIT_VALUE
#define AST_RWLIST_HEAD_STATIC(name, type) \
struct name { \
struct type *first; \
struct type *last; \
ast_rwlock_t lock; \
} name; \
static void __attribute__((constructor)) init_##name(void) \
{ \
AST_RWLIST_HEAD_INIT(&name); \
} \
static void __attribute__((destructor)) fini_##name(void) \
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
{ \
AST_RWLIST_HEAD_DESTROY(&name); \
} \
struct __dummy_##name
#else
#define AST_RWLIST_HEAD_STATIC(name, type) \
struct name { \
struct type *first; \
struct type *last; \
ast_rwlock_t lock; \
} name = AST_RWLIST_HEAD_INIT_VALUE
#endif
/*!
\brief Defines a structure to be used to hold a list of specified type, statically initialized.
This is the same as AST_LIST_HEAD_STATIC, except without the lock included.
*/
#define AST_LIST_HEAD_NOLOCK_STATIC(name, type) \
struct name { \
struct type *first; \
struct type *last; \
} name = AST_LIST_HEAD_NOLOCK_INIT_VALUE
/*!
\brief Initializes a list head structure with a specified first entry.
\param head This is a pointer to the list head structure
\param entry pointer to the list entry that will become the head of the list
This macro initializes a list head structure by setting the head
entry to the supplied value and recreating the embedded lock.
*/
#define AST_LIST_HEAD_SET(head, entry) do { \
(head)->first = (entry); \
(head)->last = (entry); \
ast_mutex_init(&(head)->lock); \
} while (0)
/*!
\brief Initializes an rwlist head structure with a specified first entry.
\param head This is a pointer to the list head structure
\param entry pointer to the list entry that will become the head of the list
This macro initializes a list head structure by setting the head
entry to the supplied value and recreating the embedded lock.
*/
#define AST_RWLIST_HEAD_SET(head, entry) do { \
(head)->first = (entry); \
(head)->last = (entry); \
ast_rwlock_init(&(head)->lock); \
} while (0)
/*!
\brief Initializes a list head structure with a specified first entry.
\param head This is a pointer to the list head structure
\param entry pointer to the list entry that will become the head of the list
This macro initializes a list head structure by setting the head
entry to the supplied value.
*/
#define AST_LIST_HEAD_SET_NOLOCK(head, entry) do { \
(head)->first = (entry); \
(head)->last = (entry); \
} while (0)
/*!
\brief Declare a forward link structure inside a list entry.
\param type This is the type of each list entry.
This macro declares a structure to be used to link list entries together.
It must be used inside the definition of the structure named in
\a type, as follows:
\code
struct list_entry {
...
AST_LIST_ENTRY(list_entry) list;
}
\endcode
The field name \a list here is arbitrary, and can be anything you wish.
*/
#define AST_LIST_ENTRY(type) \
struct { \
struct type *next; \
}
#define AST_RWLIST_ENTRY AST_LIST_ENTRY
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
/*!
\brief Returns the first entry contained in a list.
\param head This is a pointer to the list head structure
*/
#define AST_LIST_FIRST(head) ((head)->first)
#define AST_RWLIST_FIRST AST_LIST_FIRST
/*!
\brief Returns the last entry contained in a list.
\param head This is a pointer to the list head structure
*/
#define AST_LIST_LAST(head) ((head)->last)
#define AST_RWLIST_LAST AST_LIST_LAST
/*!
\brief Returns the next entry in the list after the given entry.
\param elm This is a pointer to the current entry.
\param field This is the name of the field (declared using AST_LIST_ENTRY())
used to link entries of this list together.
*/
#define AST_LIST_NEXT(elm, field) ((elm)->field.next)
#define AST_RWLIST_NEXT AST_LIST_NEXT
/*!
\brief Checks whether the specified list contains any entries.
\param head This is a pointer to the list head structure
Returns non-zero if the list has entries, zero if not.
*/
#define AST_LIST_EMPTY(head) (AST_LIST_FIRST(head) == NULL)
#define AST_RWLIST_EMPTY AST_LIST_EMPTY
/*!
\brief Loops over (traverses) the entries in a list.
\param head This is a pointer to the list head structure
\param var This is the name of the variable that will hold a pointer to the
current list entry on each iteration. It must be declared before calling
this macro.
\param field This is the name of the field (declared using AST_LIST_ENTRY())
used to link entries of this list together.
This macro is use to loop over (traverse) the entries in a list. It uses a
\a for loop, and supplies the enclosed code with a pointer to each list
entry as it loops. It is typically used as follows:
\code
static AST_LIST_HEAD(entry_list, list_entry) entries;
...
struct list_entry {
...
AST_LIST_ENTRY(list_entry) list;
}
...
struct list_entry *current;
...
AST_LIST_TRAVERSE(&entries, current, list) {
(do something with current here)
}
\endcode
\warning If you modify the forward-link pointer contained in the \a current entry while
inside the loop, the behavior will be unpredictable. At a minimum, the following
macros will modify the forward-link pointer, and should not be used inside