diff options
Diffstat (limited to 'src/ipcpd/normal/cdap_request.c')
-rw-r--r-- | src/ipcpd/normal/cdap_request.c | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/src/ipcpd/normal/cdap_request.c b/src/ipcpd/normal/cdap_request.c new file mode 100644 index 00000000..cdbbb833 --- /dev/null +++ b/src/ipcpd/normal/cdap_request.c @@ -0,0 +1,156 @@ +/* + * Ouroboros - Copyright (C) 2016 + * + * Normal IPCP - RIB Manager - CDAP request + * + * Sander Vrijders <[email protected]> + * Dimitri Staessens <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <ouroboros/config.h> +#include <ouroboros/time_utils.h> +#include <ouroboros/errno.h> + +#include "cdap_request.h" + +#include <stdlib.h> + +struct cdap_request * cdap_request_create(enum cdap_opcode code, + char * name, + int invoke_id, + struct cdap * instance) +{ + struct cdap_request * creq = malloc(sizeof(*creq)); + pthread_condattr_t cattr; + + if (creq == NULL) + return NULL; + + creq->code = code; + creq->name = name; + creq->invoke_id = invoke_id; + creq->instance = instance; + creq->state = REQ_INIT; + creq->result = -1; + + pthread_condattr_init(&cattr); + pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK); + pthread_cond_init(&creq->cond, &cattr); + pthread_mutex_init(&creq->lock, NULL); + + INIT_LIST_HEAD(&creq->next); + + return creq; +} + +void cdap_request_destroy(struct cdap_request * creq) +{ + if (creq == NULL) + return; + + pthread_mutex_lock(&creq->lock); + + if (creq->state == REQ_DESTROY) { + pthread_mutex_unlock(&creq->lock); + return; + } + + if (creq->state == REQ_INIT) + creq->state = REQ_DONE; + + if (creq->state == REQ_PENDING) { + creq->state = REQ_DESTROY; + pthread_cond_broadcast(&creq->cond); + } + + while (creq->state != REQ_DONE) + pthread_cond_wait(&creq->cond, &creq->lock); + + pthread_mutex_unlock(&creq->lock); + + pthread_cond_destroy(&creq->cond); + pthread_mutex_destroy(&creq->lock); + + if (creq->name != NULL) + free(creq->name); + + free(creq); +} + +int cdap_request_wait(struct cdap_request * creq) +{ + struct timespec timeout = {(CDAP_REPLY_TIMEOUT / 1000), + (CDAP_REPLY_TIMEOUT % 1000) * MILLION}; + struct timespec abstime; + int ret = -1; + + if (creq == NULL) + return -EINVAL; + + clock_gettime(CLOCK_REALTIME, &abstime); + ts_add(&abstime, &timeout, &abstime); + + pthread_mutex_lock(&creq->lock); + + if (creq->state != REQ_INIT) { + pthread_mutex_unlock(&creq->lock); + return -EINVAL; + } + + creq->state = REQ_PENDING; + + while (creq->state == REQ_PENDING) { + if ((ret = -pthread_cond_timedwait(&creq->cond, + &creq->lock, + &abstime)) == -ETIMEDOUT) { + break; + } + } + + if (creq->state == REQ_DESTROY) + ret = -1; + + creq->state = REQ_DONE; + pthread_cond_broadcast(&creq->cond); + + pthread_mutex_unlock(&creq->lock); + + return ret; +} + +void cdap_request_respond(struct cdap_request * creq, + int response) +{ + if (creq == NULL) + return; + + pthread_mutex_lock(&creq->lock); + + if (creq->state != REQ_PENDING) { + pthread_mutex_unlock(&creq->lock); + return; + } + + creq->state = REQ_RESPONSE; + creq->result = response; + pthread_cond_broadcast(&creq->cond); + + while (creq->state == REQ_RESPONSE) + pthread_cond_wait(&creq->cond, &creq->lock); + + pthread_mutex_unlock(&creq->lock); +} |