command.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2013, Digium, Inc.
00005  *
00006  * David M. Lee, II <dlee@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Stasis application command support.
00022  *
00023  * \author David M. Lee, II <dlee@digium.com>
00024  */
00025 
00026 #include "asterisk.h"
00027 
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 421881 $")
00029 
00030 #include "command.h"
00031 
00032 #include "asterisk/lock.h"
00033 #include "asterisk/stasis_app_impl.h"
00034 
00035 struct stasis_app_command {
00036    ast_mutex_t lock;
00037    ast_cond_t condition;
00038    stasis_app_command_cb callback;
00039    void *data;
00040    command_data_destructor_fn data_destructor;
00041    int retval;
00042    int is_done:1;
00043 };
00044 
00045 static void command_dtor(void *obj)
00046 {
00047    struct stasis_app_command *command = obj;
00048 
00049    if (command->data_destructor) {
00050       command->data_destructor(command->data);
00051    }
00052 
00053    ast_mutex_destroy(&command->lock);
00054    ast_cond_destroy(&command->condition);
00055 }
00056 
00057 struct stasis_app_command *command_create(
00058    stasis_app_command_cb callback, void *data, command_data_destructor_fn data_destructor)
00059 {
00060    struct stasis_app_command *command;
00061 
00062    command = ao2_alloc(sizeof(*command), command_dtor);
00063    if (!command) {
00064       if (data_destructor) {
00065          data_destructor(data);
00066       }
00067       return NULL;
00068    }
00069 
00070    ast_mutex_init(&command->lock);
00071    ast_cond_init(&command->condition, 0);
00072    command->callback = callback;
00073    command->data = data;
00074    command->data_destructor = data_destructor;
00075 
00076    return command;
00077 }
00078 
00079 void command_complete(struct stasis_app_command *command, int retval)
00080 {
00081    SCOPED_MUTEX(lock, &command->lock);
00082 
00083    command->is_done = 1;
00084    command->retval = retval;
00085    ast_cond_signal(&command->condition);
00086 }
00087 
00088 int command_join(struct stasis_app_command *command)
00089 {
00090    SCOPED_MUTEX(lock, &command->lock);
00091    while (!command->is_done) {
00092       ast_cond_wait(&command->condition, &command->lock);
00093    }
00094 
00095    return command->retval;
00096 }
00097 
00098 void command_invoke(struct stasis_app_command *command,
00099    struct stasis_app_control *control, struct ast_channel *chan)
00100 {
00101    int retval = command->callback(control, chan, command->data);
00102    if (command->data_destructor) {
00103       command->data_destructor(command->data);
00104       command->data_destructor = NULL;
00105    }
00106    command_complete(command, retval);
00107 }
00108 
00109 static void command_queue_prestart_destroy(void *obj)
00110 {
00111    /* Clean up the container */
00112    ao2_cleanup(obj);
00113 }
00114 
00115 static const struct ast_datastore_info command_queue_prestart = {
00116    .type = "stasis-command-prestart-queue",
00117    .destroy = command_queue_prestart_destroy,
00118 };
00119 
00120 int command_prestart_queue_command(struct ast_channel *chan,
00121    stasis_app_command_cb command_fn, void *data, command_data_destructor_fn data_destructor)
00122 {
00123    struct ast_datastore *datastore;
00124    struct ao2_container *command_queue;
00125    RAII_VAR(struct stasis_app_command *, command,
00126       command_create(command_fn, data, data_destructor), ao2_cleanup);
00127 
00128    if (!command) {
00129       return -1;
00130    }
00131 
00132    datastore = ast_channel_datastore_find(chan, &command_queue_prestart, NULL);
00133    if (datastore) {
00134       command_queue = datastore->data;
00135       ao2_link(command_queue, command);
00136       return 0;
00137    }
00138 
00139    command_queue = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, NULL);
00140    if (!command_queue) {
00141       return -1;
00142    }
00143 
00144    datastore = ast_datastore_alloc(&command_queue_prestart, NULL);
00145    if (!datastore) {
00146       ao2_cleanup(command_queue);
00147       return -1;
00148    }
00149    ast_channel_datastore_add(chan, datastore);
00150 
00151    datastore->data = command_queue;
00152    ao2_link(command_queue, command);
00153 
00154    return 0;
00155 }
00156 
00157 struct ao2_container *command_prestart_get_container(struct ast_channel *chan)
00158 {
00159    struct ast_datastore *datastore = ast_channel_datastore_find(chan, &command_queue_prestart, NULL);
00160 
00161    if (!datastore) {
00162       return NULL;
00163    }
00164 
00165    return ao2_bump(datastore->data);
00166 }

Generated on Thu Apr 16 06:27:30 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6