command.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  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. ast_mutex_lock(&command->lock);
  68. command->is_done = 1;
  69. command->retval = retval;
  70. ast_cond_signal(&command->condition);
  71. ast_mutex_unlock(&command->lock);
  72. }
  73. int command_join(struct stasis_app_command *command)
  74. {
  75. int ret;
  76. ast_mutex_lock(&command->lock);
  77. while (!command->is_done) {
  78. ast_cond_wait(&command->condition, &command->lock);
  79. }
  80. ret = command->retval;
  81. ast_mutex_unlock(&command->lock);
  82. return ret;
  83. }
  84. void command_invoke(struct stasis_app_command *command,
  85. struct stasis_app_control *control, struct ast_channel *chan)
  86. {
  87. int retval = command->callback(control, chan, command->data);
  88. if (command->data_destructor) {
  89. command->data_destructor(command->data);
  90. command->data_destructor = NULL;
  91. }
  92. command_complete(command, retval);
  93. }
  94. static void command_queue_prestart_destroy(void *obj)
  95. {
  96. /* Clean up the container */
  97. ao2_cleanup(obj);
  98. }
  99. static const struct ast_datastore_info command_queue_prestart = {
  100. .type = "stasis-command-prestart-queue",
  101. .destroy = command_queue_prestart_destroy,
  102. };
  103. int command_prestart_queue_command(struct ast_channel *chan,
  104. stasis_app_command_cb command_fn, void *data, command_data_destructor_fn data_destructor)
  105. {
  106. struct ast_datastore *datastore;
  107. struct ao2_container *command_queue;
  108. RAII_VAR(struct stasis_app_command *, command,
  109. command_create(command_fn, data, data_destructor), ao2_cleanup);
  110. if (!command) {
  111. return -1;
  112. }
  113. datastore = ast_channel_datastore_find(chan, &command_queue_prestart, NULL);
  114. if (datastore) {
  115. command_queue = datastore->data;
  116. ao2_link(command_queue, command);
  117. return 0;
  118. }
  119. command_queue = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, NULL);
  120. if (!command_queue) {
  121. return -1;
  122. }
  123. datastore = ast_datastore_alloc(&command_queue_prestart, NULL);
  124. if (!datastore) {
  125. ao2_cleanup(command_queue);
  126. return -1;
  127. }
  128. ast_channel_datastore_add(chan, datastore);
  129. datastore->data = command_queue;
  130. ao2_link(command_queue, command);
  131. return 0;
  132. }
  133. struct ao2_container *command_prestart_get_container(struct ast_channel *chan)
  134. {
  135. struct ast_datastore *datastore = ast_channel_datastore_find(chan, &command_queue_prestart, NULL);
  136. if (!datastore) {
  137. return NULL;
  138. }
  139. return ao2_bump(datastore->data);
  140. }