Asterisk - The Open Source Telephony Project  18.5.0
Data Structures | Functions | Variables
func_lock.c File Reference

Dialplan mutexes. More...

#include "asterisk.h"
#include <signal.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/linkedlists.h"
#include "asterisk/astobj2.h"
#include "asterisk/utils.h"
#include "asterisk/cli.h"
Include dependency graph for func_lock.c:

Go to the source code of this file.

Data Structures

struct  channel_lock_frame
 
struct  lock_frame
 
struct  locklist
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static int get_lock (struct ast_channel *chan, char *lockname, int trylock)
 
static char * handle_cli_locks_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static int load_module (void)
 
static void lock_fixup (void *data, struct ast_channel *oldchan, struct ast_channel *newchan)
 
static void lock_free (void *data)
 
static int lock_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 
static int trylock_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 
static int unload_module (void)
 
static int unlock_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Dialplan mutexes" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "30ef0c93b36035ec78c9cfd712d36d9b" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_cli_entry cli_locks_show = { .handler = handle_cli_locks_show , .summary = "List func_lock locks." ,}
 
static struct ast_custom_function lock_function
 
static const struct ast_datastore_info lock_info
 
static struct locklist locklist = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }
 
static struct ast_custom_function trylock_function
 
static int unloading = 0
 
static struct ast_custom_function unlock_function
 

Detailed Description

Dialplan mutexes.

Author
Tilghman Lesher func_.nosp@m.lock.nosp@m._2007.nosp@m.@the.nosp@m.-tilg.nosp@m.hman.nosp@m..com

Definition in file func_lock.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 542 of file func_lock.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 542 of file func_lock.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 542 of file func_lock.c.

◆ get_lock()

static int get_lock ( struct ast_channel chan,
char *  lockname,
int  trylock 
)
static

Definition at line 186 of file func_lock.c.

References ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_cond_init, ast_cond_signal, ast_cond_timedwait, ast_datastore_alloc, ast_datastore_free(), ast_free, AST_LIST_HEAD, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, ast_module_ref, ast_mutex_destroy, ast_mutex_init, ast_mutex_lock, ast_mutex_unlock, ast_tvnow(), channel_lock_frame::channel, lock_frame::cond, lock_frame::count, ast_datastore::data, lock_frame::entries, channel_lock_frame::list, channel_lock_frame::lock_frame, LOG_ERROR, lock_frame::mutex, lock_frame::name, NULL, lock_frame::owner, lock_frame::requesters, ast_module_info::self, and unloading.

Referenced by lock_read(), and trylock_read().

187 {
188  struct ast_datastore *lock_store = ast_channel_datastore_find(chan, &lock_info, NULL);
189  struct lock_frame *current;
190  struct channel_lock_frame *clframe = NULL;
192  int res = 0;
193  struct timespec timeout = { 0, };
194  struct timeval now;
195 
196  if (!lock_store) {
197  if (unloading) {
198  ast_log(LOG_ERROR, "%sLOCK has no datastore and func_lock is unloading, failing.\n",
199  trylock ? "TRY" : "");
200  return -1;
201  }
202 
203  lock_store = ast_datastore_alloc(&lock_info, NULL);
204  if (!lock_store) {
205  ast_log(LOG_ERROR, "Unable to allocate new datastore. No locks will be obtained.\n");
206  return -1;
207  }
208 
209  list = ast_calloc(1, sizeof(*list));
210  if (!list) {
212  "Unable to allocate datastore list head. %sLOCK will fail.\n",
213  trylock ? "TRY" : "");
214  ast_datastore_free(lock_store);
215  return -1;
216  }
217 
218  lock_store->data = list;
219  AST_LIST_HEAD_INIT(list);
220  ast_channel_datastore_add(chan, lock_store);
221 
222  /* We cannot unload until this channel has released the lock_store */
224  } else
225  list = lock_store->data;
226 
227  /* Lock already exists? */
229  AST_LIST_TRAVERSE(&locklist, current, entries) {
230  if (strcmp(current->name, lockname) == 0) {
231  break;
232  }
233  }
234 
235  if (!current) {
236  if (unloading) {
238  "Lock doesn't exist whilst unloading. %sLOCK will fail.\n",
239  trylock ? "TRY" : "");
240  /* Don't bother */
242  return -1;
243  }
244 
245  /* Create new lock entry */
246  current = ast_calloc(1, sizeof(*current) + strlen(lockname) + 1);
247  if (!current) {
249  return -1;
250  }
251 
252  strcpy(current->name, lockname); /* SAFE */
253  if ((res = ast_mutex_init(&current->mutex))) {
254  ast_log(LOG_ERROR, "Unable to initialize mutex: %s\n", strerror(res));
255  ast_free(current);
257  return -1;
258  }
259  if ((res = ast_cond_init(&current->cond, NULL))) {
260  ast_log(LOG_ERROR, "Unable to initialize condition variable: %s\n", strerror(res));
261  ast_mutex_destroy(&current->mutex);
262  ast_free(current);
264  return -1;
265  }
266  AST_LIST_INSERT_TAIL(&locklist, current, entries);
267  }
268  /* Add to requester list */
269  ast_mutex_lock(&current->mutex);
270  current->requesters++;
271  ast_mutex_unlock(&current->mutex);
273 
274  /* Found lock or created one - now find or create the corresponding link in the channel */
275  AST_LIST_LOCK(list);
276  AST_LIST_TRAVERSE(list, clframe, list) {
277  if (clframe->lock_frame == current) {
278  break;
279  }
280  }
281 
282  if (!clframe) {
283  if (unloading) {
285  "Busy unloading. %sLOCK will fail.\n",
286  trylock ? "TRY" : "");
287  /* Don't bother */
288  ast_mutex_lock(&current->mutex);
289  current->requesters--;
290  ast_mutex_unlock(&current->mutex);
291  AST_LIST_UNLOCK(list);
292  return -1;
293  }
294 
295  if (!(clframe = ast_calloc(1, sizeof(*clframe)))) {
297  "Unable to allocate channel lock frame. %sLOCK will fail.\n",
298  trylock ? "TRY" : "");
299  ast_mutex_lock(&current->mutex);
300  current->requesters--;
301  ast_mutex_unlock(&current->mutex);
302  AST_LIST_UNLOCK(list);
303  return -1;
304  }
305 
306  clframe->lock_frame = current;
307  clframe->channel = chan;
308  AST_LIST_INSERT_TAIL(list, clframe, list);
309  }
310  AST_LIST_UNLOCK(list);
311 
312  /* If we already own the lock, then we're being called recursively.
313  * Keep track of how many times that is, because we need to unlock
314  * the same amount, before we'll release this one.
315  */
316  if (current->owner == chan) {
317  /* We're not a requester, we already have it */
318  ast_mutex_lock(&current->mutex);
319  current->requesters--;
320  ast_mutex_unlock(&current->mutex);
321  current->count++;
322  return 0;
323  }
324 
325  /* Wait up to three seconds from now for LOCK. */
326  now = ast_tvnow();
327  timeout.tv_sec = now.tv_sec + 3;
328  timeout.tv_nsec = now.tv_usec * 1000;
329 
330  ast_mutex_lock(&current->mutex);
331 
332  res = 0;
333  while (!trylock && !res && current->owner) {
334  res = ast_cond_timedwait(&current->cond, &current->mutex, &timeout);
335  }
336  if (current->owner) {
337  /* timeout;
338  * trylock; or
339  * cond_timedwait failed.
340  *
341  * either way, we fail to obtain the lock.
342  */
343  res = -1;
344  } else {
345  current->owner = chan;
346  current->count++;
347  res = 0;
348  }
349  /* Remove from requester list */
350  current->requesters--;
351  if (res && unloading)
352  ast_cond_signal(&current->cond);
353  ast_mutex_unlock(&current->mutex);
354 
355  return res;
356 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:172
static int unloading
Definition: func_lock.c:113
struct lock_frame * lock_frame
Definition: func_lock.c:139
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
static int timeout
Definition: cdr_mysql.c:86
#define ast_cond_init(cond, attr)
Definition: lock.h:199
unsigned int requesters
Definition: func_lock.c:128
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
#define ast_mutex_lock(a)
Definition: lock.h:187
Structure for a data store object.
Definition: datastore.h:68
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2404
#define NULL
Definition: resample.c:96
#define ast_cond_signal(cond)
Definition: lock.h:201
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
#define ast_log
Definition: astobj2.c:42
struct ast_module * self
Definition: module.h:342
static const struct ast_datastore_info lock_info
Definition: func_lock.c:115
#define LOG_ERROR
Definition: logger.h:285
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
ast_mutex_t mutex
Definition: func_lock.c:123
ast_cond_t cond
Definition: func_lock.c:124
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:625
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
char name[0]
Definition: func_lock.c:132
void * data
Definition: datastore.h:70
struct ast_channel * owner
Definition: func_lock.c:130
struct ast_channel * channel
Definition: func_lock.c:138
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:89
#define ast_mutex_init(pmutex)
Definition: lock.h:184
#define ast_mutex_destroy(a)
Definition: lock.h:186
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2390
#define ast_cond_timedwait(cond, mutex, time)
Definition: lock.h:204
unsigned int count
Definition: func_lock.c:126
struct channel_lock_frame::@211 list
#define ast_mutex_unlock(a)
Definition: lock.h:188
#define ast_module_ref(mod)
Hold a reference to the module.
Definition: module.h:443

◆ handle_cli_locks_show()

static char* handle_cli_locks_show ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 434 of file func_lock.c.

References ast_channel_name(), ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, c, CLI_GENERATE, CLI_INIT, ast_cli_entry::command, lock_frame::entries, ast_cli_args::fd, lock_frame::mutex, lock_frame::name, NULL, lock_frame::owner, lock_frame::requesters, and ast_cli_entry::usage.

435 {
436  int c = 0;
437  struct lock_frame* current;
438  switch (cmd) {
439  case CLI_INIT:
440  e->command = "dialplan locks show";
441  e->usage =
442  "Usage: dialplan locks show\n"
443  " List all locks known to func_lock, along with their current status.\n";
444  return NULL;
445  case CLI_GENERATE:
446  return NULL;
447  }
448 
449  ast_cli(a->fd, "func_lock locks:\n");
450  ast_cli(a->fd, "%-40s Requesters Owner\n", "Name");
452  AST_LIST_TRAVERSE(&locklist, current, entries) {
453  ast_mutex_lock(&current->mutex);
454  ast_cli(a->fd, "%-40s %-10d %s\n", current->name, current->requesters,
455  current->owner ? ast_channel_name(current->owner) : "(unlocked)");
456  ast_mutex_unlock(&current->mutex);
457  c++;
458  }
460  ast_cli(a->fd, "%d total locks listed.\n", c);
461 
462  return 0;
463 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
struct lock_frame::@210 entries
Definition: cli.h:152
unsigned int requesters
Definition: func_lock.c:128
#define ast_mutex_lock(a)
Definition: lock.h:187
static struct test_val c
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
const int fd
Definition: cli.h:159
ast_mutex_t mutex
Definition: func_lock.c:123
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
char * command
Definition: cli.h:186
char name[0]
Definition: func_lock.c:132
const char * usage
Definition: cli.h:177
struct ast_channel * owner
Definition: func_lock.c:130
const char * ast_channel_name(const struct ast_channel *chan)
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ load_module()

static int load_module ( void  )
static

Definition at line 532 of file func_lock.c.

References AST_CFE_READ, ast_cli_register, and ast_custom_function_register_escalating.

533 {
538 
539  return res;
540 }
static struct ast_custom_function trylock_function
Definition: func_lock.c:471
#define ast_cli_register(e)
Registers a command or an array of commands.
Definition: cli.h:256
#define ast_custom_function_register_escalating(acf, escalation)
Register a custom function which requires escalated privileges.
Definition: pbx.h:1517
static struct ast_cli_entry cli_locks_show
Definition: func_lock.c:483
static struct ast_custom_function unlock_function
Definition: func_lock.c:477
static struct ast_custom_function lock_function
Definition: func_lock.c:465

◆ lock_fixup()

static void lock_fixup ( void *  data,
struct ast_channel oldchan,
struct ast_channel newchan 
)
static

Definition at line 165 of file func_lock.c.

References ast_channel_datastore_find(), AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, channel_lock_frame::channel, ast_datastore::data, channel_lock_frame::list, channel_lock_frame::lock_frame, NULL, and lock_frame::owner.

166 {
167  struct ast_datastore *lock_store = ast_channel_datastore_find(oldchan, &lock_info, NULL);
169  struct channel_lock_frame *clframe = NULL;
170 
171  if (!lock_store) {
172  return;
173  }
174  list = lock_store->data;
175 
177  AST_LIST_TRAVERSE(list, clframe, list) {
178  if (clframe->lock_frame->owner == oldchan) {
179  clframe->lock_frame->owner = newchan;
180  }
181  clframe->channel = newchan;
182  }
184 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:172
struct lock_frame * lock_frame
Definition: func_lock.c:139
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
Structure for a data store object.
Definition: datastore.h:68
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2404
#define NULL
Definition: resample.c:96
static const struct ast_datastore_info lock_info
Definition: func_lock.c:115
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
void * data
Definition: datastore.h:70
struct ast_channel * owner
Definition: func_lock.c:130
struct ast_channel * channel
Definition: func_lock.c:138
struct channel_lock_frame::@211 list

◆ lock_free()

static void lock_free ( void *  data)
static

Definition at line 142 of file func_lock.c.

References ast_cond_signal, ast_free, AST_LIST_HEAD, AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_module_unref, ast_mutex_lock, ast_mutex_unlock, channel_lock_frame::channel, lock_frame::cond, lock_frame::count, channel_lock_frame::list, channel_lock_frame::lock_frame, lock_frame::mutex, NULL, lock_frame::owner, and ast_module_info::self.

143 {
144  AST_LIST_HEAD(, channel_lock_frame) *oldlist = data;
145  struct channel_lock_frame *clframe;
146  AST_LIST_LOCK(oldlist);
147  while ((clframe = AST_LIST_REMOVE_HEAD(oldlist, list))) {
148  /* Only unlock if we own the lock */
149  if (clframe->channel == clframe->lock_frame->owner) {
150  ast_mutex_lock(&clframe->lock_frame->mutex);
151  clframe->lock_frame->count = 0;
152  clframe->lock_frame->owner = NULL;
153  ast_cond_signal(&clframe->lock_frame->cond);
154  ast_mutex_unlock(&clframe->lock_frame->mutex);
155  }
156  ast_free(clframe);
157  }
158  AST_LIST_UNLOCK(oldlist);
159  AST_LIST_HEAD_DESTROY(oldlist);
160  ast_free(oldlist);
161 
163 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:172
struct lock_frame * lock_frame
Definition: func_lock.c:139
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
#define ast_mutex_lock(a)
Definition: lock.h:187
#define NULL
Definition: resample.c:96
#define ast_cond_signal(cond)
Definition: lock.h:201
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:469
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
Definition: linkedlists.h:652
struct ast_module * self
Definition: module.h:342
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
ast_mutex_t mutex
Definition: func_lock.c:123
ast_cond_t cond
Definition: func_lock.c:124
#define ast_free(a)
Definition: astmm.h:182
struct ast_channel * owner
Definition: func_lock.c:130
struct ast_channel * channel
Definition: func_lock.c:138
unsigned int count
Definition: func_lock.c:126
struct channel_lock_frame::@211 list
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ lock_read()

static int lock_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
)
static

Definition at line 410 of file func_lock.c.

References ast_autoservice_start(), ast_autoservice_stop(), ast_copy_string(), and get_lock().

411 {
412  if (!chan) {
413  return -1;
414  }
415  ast_autoservice_start(chan);
416  ast_copy_string(buf, get_lock(chan, data, 0) ? "0" : "1", len);
417  ast_autoservice_stop(chan);
418 
419  return 0;
420 }
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
static int get_lock(struct ast_channel *chan, char *lockname, int trylock)
Definition: func_lock.c:186
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401

◆ trylock_read()

static int trylock_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
)
static

Definition at line 422 of file func_lock.c.

References ast_autoservice_start(), ast_autoservice_stop(), ast_copy_string(), and get_lock().

423 {
424  if (!chan) {
425  return -1;
426  }
427  ast_autoservice_start(chan);
428  ast_copy_string(buf, get_lock(chan, data, 1) ? "0" : "1", len);
429  ast_autoservice_stop(chan);
430 
431  return 0;
432 }
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
static int get_lock(struct ast_channel *chan, char *lockname, int trylock)
Definition: func_lock.c:186
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 485 of file func_lock.c.

References ast_cli_unregister(), ast_cond_destroy, ast_cond_wait, ast_custom_function_unregister(), ast_free, AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log, ast_mutex_destroy, ast_mutex_lock, ast_mutex_unlock, lock_frame::cond, lock_frame::entries, LOG_WARNING, lock_frame::mutex, lock_frame::name, lock_frame::owner, lock_frame::requesters, and unloading.

486 {
487  struct lock_frame *current;
488 
489  /* Module flag */
490  unloading = 1;
491 
492  /* Make it impossible for new requesters to be added
493  * NOTE: channels could already be in get_lock() */
496 
498 
500  while ((current = AST_LIST_REMOVE_HEAD(&locklist, entries))) {
501  int warned = 0;
502  ast_mutex_lock(&current->mutex);
503  while (current->owner || current->requesters) {
504  if (!warned) {
505  ast_log(LOG_WARNING, "Waiting for %d requesters for %s lock %s.\n",
506  current->requesters, current->owner ? "locked" : "unlocked",
507  current->name);
508  warned = 1;
509  }
510  /* either the mutex is locked, or other parties are currently in get_lock,
511  * we need to wait for all of those to clear first */
512  ast_cond_wait(&current->cond, &current->mutex);
513  }
514  ast_mutex_unlock(&current->mutex);
515  /* At this point we know:
516  * 1. the lock has been released,
517  * 2. there are no requesters (nor should any be able to sneak in).
518  */
519  ast_mutex_destroy(&current->mutex);
520  ast_cond_destroy(&current->cond);
521  ast_free(current);
522  }
525 
526  /* At this point we can safely stop access to UNLOCK */
528 
529  return 0;
530 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
static int unloading
Definition: func_lock.c:113
int ast_cli_unregister(struct ast_cli_entry *e)
Unregisters a command or an array of commands.
Definition: main/cli.c:2397
#define LOG_WARNING
Definition: logger.h:274
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
struct lock_frame::@210 entries
static struct ast_custom_function trylock_function
Definition: func_lock.c:471
#define ast_cond_wait(cond, mutex)
Definition: lock.h:203
unsigned int requesters
Definition: func_lock.c:128
#define ast_mutex_lock(a)
Definition: lock.h:187
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
Definition: linkedlists.h:652
#define ast_log
Definition: astobj2.c:42
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
ast_mutex_t mutex
Definition: func_lock.c:123
#define ast_cond_destroy(cond)
Definition: lock.h:200
ast_cond_t cond
Definition: func_lock.c:124
#define ast_free(a)
Definition: astmm.h:182
static struct ast_cli_entry cli_locks_show
Definition: func_lock.c:483
char name[0]
Definition: func_lock.c:132
static struct ast_custom_function unlock_function
Definition: func_lock.c:477
struct ast_channel * owner
Definition: func_lock.c:130
#define ast_mutex_destroy(a)
Definition: lock.h:186
static struct ast_custom_function lock_function
Definition: func_lock.c:465
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ unlock_read()

static int unlock_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
)
static

Definition at line 358 of file func_lock.c.

References ast_channel_datastore_find(), ast_cond_signal, ast_copy_string(), ast_debug, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, ast_mutex_lock, ast_mutex_unlock, lock_frame::cond, lock_frame::count, ast_datastore::data, channel_lock_frame::list, channel_lock_frame::lock_frame, LOG_WARNING, lock_frame::mutex, lock_frame::name, NULL, and lock_frame::owner.

359 {
360  struct ast_datastore *lock_store;
361  struct channel_lock_frame *clframe;
363 
364  if (!chan) {
365  return -1;
366  }
367 
368  lock_store = ast_channel_datastore_find(chan, &lock_info, NULL);
369  if (!lock_store) {
370  ast_log(LOG_WARNING, "No datastore for dialplan locks. Nothing was ever locked!\n");
371  ast_copy_string(buf, "0", len);
372  return 0;
373  }
374 
375  if (!(list = lock_store->data)) {
376  ast_debug(1, "This should NEVER happen\n");
377  ast_copy_string(buf, "0", len);
378  return 0;
379  }
380 
381  /* Find item in the channel list */
383  AST_LIST_TRAVERSE(list, clframe, list) {
384  if (clframe->lock_frame && clframe->lock_frame->owner == chan && strcmp(clframe->lock_frame->name, data) == 0) {
385  break;
386  }
387  }
388  /* We never destroy anything until channel destruction, which will never
389  * happen while this routine is executing, so we don't need to hold the
390  * lock beyond this point. */
392 
393  if (!clframe) {
394  /* We didn't have this lock in the first place */
395  ast_copy_string(buf, "0", len);
396  return 0;
397  }
398 
399  if (--clframe->lock_frame->count == 0) {
400  ast_mutex_lock(&clframe->lock_frame->mutex);
401  clframe->lock_frame->owner = NULL;
402  ast_cond_signal(&clframe->lock_frame->cond);
403  ast_mutex_unlock(&clframe->lock_frame->mutex);
404  }
405 
406  ast_copy_string(buf, "1", len);
407  return 0;
408 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:172
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
struct lock_frame * lock_frame
Definition: func_lock.c:139
#define LOG_WARNING
Definition: logger.h:274
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
#define ast_mutex_lock(a)
Definition: lock.h:187
Structure for a data store object.
Definition: datastore.h:68
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2404
#define NULL
Definition: resample.c:96
#define ast_cond_signal(cond)
Definition: lock.h:201
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
static const struct ast_datastore_info lock_info
Definition: func_lock.c:115
ast_mutex_t mutex
Definition: func_lock.c:123
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
ast_cond_t cond
Definition: func_lock.c:124
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
char name[0]
Definition: func_lock.c:132
void * data
Definition: datastore.h:70
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
struct ast_channel * owner
Definition: func_lock.c:130
unsigned int count
Definition: func_lock.c:126
struct channel_lock_frame::@211 list
#define ast_mutex_unlock(a)
Definition: lock.h:188

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Dialplan mutexes" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "30ef0c93b36035ec78c9cfd712d36d9b" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
static

Definition at line 542 of file func_lock.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 542 of file func_lock.c.

◆ cli_locks_show

struct ast_cli_entry cli_locks_show = { .handler = handle_cli_locks_show , .summary = "List func_lock locks." ,}
static

Definition at line 483 of file func_lock.c.

◆ lock_function

struct ast_custom_function lock_function
static
Initial value:
= {
.name = "LOCK",
.read = lock_read,
.read_max = 2,
}
static int lock_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_lock.c:410

Definition at line 465 of file func_lock.c.

◆ lock_info

const struct ast_datastore_info lock_info
static
Initial value:
= {
.type = "MUTEX",
.destroy = lock_free,
.chan_fixup = lock_fixup,
}
static void lock_free(void *data)
Definition: func_lock.c:142
static void lock_fixup(void *data, struct ast_channel *oldchan, struct ast_channel *newchan)
Definition: func_lock.c:165

Definition at line 115 of file func_lock.c.

Referenced by ast_dump_locks(), ast_find_lock_info(), ast_log_show_lock(), ast_mark_lock_acquired(), ast_mark_lock_failed(), ast_remove_lock_info(), ast_restore_lock_info(), ast_store_lock_info(), ast_suspend_lock_info(), dummy_start(), and lock_info_destroy().

◆ locklist

struct locklist locklist = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }
static

◆ trylock_function

struct ast_custom_function trylock_function
static
Initial value:
= {
.name = "TRYLOCK",
.read = trylock_read,
.read_max = 2,
}
static int trylock_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_lock.c:422

Definition at line 471 of file func_lock.c.

◆ unloading

int unloading = 0
static

Definition at line 113 of file func_lock.c.

Referenced by get_lock(), and unload_module().

◆ unlock_function

struct ast_custom_function unlock_function
static
Initial value:
= {
.name = "UNLOCK",
.read = unlock_read,
.read_max = 2,
}
static int unlock_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_lock.c:358

Definition at line 477 of file func_lock.c.