command.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2013, Digium, Inc.
  5. *
  6. * David M. Lee, II <dlee@digium.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. /*! \file
  19. *
  20. * \brief Stasis application command support.
  21. *
  22. * \author David M. Lee, II <dlee@digium.com>
  23. */
  24. #include "asterisk.h"
  25. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  26. #include "command.h"
  27. #include "asterisk/lock.h"
  28. #include "asterisk/stasis_app_impl.h"
  29. struct stasis_app_command {
  30. ast_mutex_t lock;
  31. ast_cond_t condition;
  32. stasis_app_command_cb callback;
  33. void *data;
  34. command_data_destructor_fn data_destructor;
  35. int retval;
  36. int is_done:1;
  37. };
  38. static void command_dtor(void *obj)
  39. {
  40. struct stasis_app_command *command = obj;
  41. if (command->data_destructor) {
  42. command->data_destructor(command->data);
  43. }
  44. ast_mutex_destroy(&command->lock);
  45. ast_cond_destroy(&command->condition);
  46. }
  47. struct stasis_app_command *command_create(
  48. stasis_app_command_cb callback, void *data, command_data_destructor_fn data_destructor)
  49. {
  50. struct stasis_app_command *command;
  51. command = ao2_alloc(sizeof(*command), command_dtor);
  52. if (!command) {
  53. if (data_destructor) {
  54. data_destructor(data);
  55. }
  56. return NULL;
  57. }
  58. ast_mutex_init(&command->lock);
  59. ast_cond_init(&command->condition, 0);
  60. command->callback = callback;
  61. command->data = data;
  62. command->data_destructor = data_destructor;
  63. return command;
  64. }
  65. void command_complete(struct stasis_app_command *command, int retval)
  66. {
  67. SCOPED_MUTEX(lock, &command->lock);
  68. command->is_done = 1;
  69. command->retval = retval;
  70. ast_cond_signal(&command->condition);
  71. }
  72. int command_join(struct stasis_app_command *command)
  73. {
  74. SCOPED_MUTEX(lock, &command->lock);
  75. while (!command->is_done) {
  76. ast_cond_wait(&command->condition, &command->lock);
  77. }
  78. return command->retval;
  79. }
  80. void command_invoke(struct stasis_app_command *command,
  81. struct stasis_app_control *control, struct ast_channel *chan)
  82. {
  83. int retval = command->callback(control, chan, command->data);
  84. if (command->data_destructor) {
  85. command->data_destructor(command->data);
  86. command->data_destructor = NULL;
  87. }
  88. command_complete(command, retval);
  89. }
  90. static void command_queue_prestart_destroy(void *obj)
  91. {
  92. /* Clean up the container */
  93. ao2_cleanup(obj);
  94. }
  95. static const struct ast_datastore_info command_queue_prestart = {
  96. .type = "stasis-command-prestart-queue",
  97. .destroy = command_queue_prestart_destroy,
  98. };
  99. int command_prestart_queue_command(struct ast_channel *chan,
  100. stasis_app_command_cb command_fn, void *data, command_data_destructor_fn data_destructor)
  101. {
  102. struct ast_datastore *datastore;
  103. struct ao2_container *command_queue;
  104. RAII_VAR(struct stasis_app_command *, command,
  105. command_create(command_fn, data, data_destructor), ao2_cleanup);
  106. if (!command) {
  107. return -1;
  108. }
  109. datastore = ast_channel_datastore_find(chan, &command_queue_prestart, NULL);
  110. if (datastore) {
  111. command_queue = datastore->data;
  112. ao2_link(command_queue, command);
  113. return 0;
  114. }
  115. command_queue = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, NULL);
  116. if (!command_queue) {
  117. return -1;
  118. }
  119. datastore = ast_datastore_alloc(&command_queue_prestart, NULL);
  120. if (!datastore) {
  121. ao2_cleanup(command_queue);
  122. return -1;
  123. }
  124. ast_channel_datastore_add(chan, datastore);
  125. datastore->data = command_queue;
  126. ao2_link(command_queue, command);
  127. return 0;
  128. }
  129. struct ao2_container *command_prestart_get_container(struct ast_channel *chan)
  130. {
  131. struct ast_datastore *datastore = ast_channel_datastore_find(chan, &command_queue_prestart, NULL);
  132. if (!datastore) {
  133. return NULL;
  134. }
  135. return ao2_bump(datastore->data);
  136. }