1/*2 * Copyright © 2016-2019 Sören Tempel3 *4 * This program is free software: you can redistribute it and/or5 * modify it under the terms of the GNU Affero General Public6 * License as published by the Free Software Foundation, either7 * version 3 of the License, or (at your option) any later version.8 *9 * This program is distributed in the hope that it will be useful,10 * but WITHOUT ANY WARRANTY; without even the implied warranty of11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU12 * Affero General Public License for more details.13 *14 * You should have received a copy of the GNU Affero General Public15 * License along with this program. If not, see16 * <http://www.gnu.org/licenses/>.17 */1819#include <assert.h>20#include <errno.h>21#include <pthread.h>22#include <semaphore.h>23#include <stdlib.h>2425#include "queue.h"26#include "token.h"27#include "util.h"2829/**30 * Allocates memory for a new queue and initializes it.31 *32 * @returns A pointer to the newly created queue.33 */34queue *35newqueue(void)36{37 queue *qu;3839 qu = emalloc(sizeof(queue));40 qu->head = qu->tail = 0;4142 if ((errno = pthread_mutex_init(&qu->hmtx, NULL)) ||43 (errno = pthread_mutex_init(&qu->tmtx, NULL)))44 die("pthread_mutex_init failed");4546 if (sem_init(&qu->fullsem, 0, 0) ||47 sem_init(&qu->emptysem, 0, NUMTOKENS))48 die("sem_init failed");4950 return qu;51}5253/**54 * Enqueues a new token at the end of this queue.55 *56 * @pre Token must not be NULL.57 * @param qu Queue where token should be enqueued.58 * @param value Token which should be enqueued.59 */60void61enqueue(queue *qu, token *value)62{63 sem_ewait(&qu->emptysem);64 pthread_mutex_elock(&qu->tmtx);65 qu->tokens[qu->tail++ % NUMTOKENS] = value;66 pthread_mutex_eunlock(&qu->tmtx);67 sem_epost(&qu->fullsem);68}6970/**71 * Dequeues the least recently added token from this queue.72 * Causes a deadlock if you already dequeued the last item from this queue.73 *74 * @returns Pointer to the least recently added token.75 */76token *77dequeue(queue *qu)78{79 token *ret;8081 sem_ewait(&qu->fullsem);82 pthread_mutex_elock(&qu->hmtx);83 ret = qu->tokens[qu->head++ % NUMTOKENS];84 pthread_mutex_eunlock(&qu->hmtx);85 sem_epost(&qu->emptysem);8687 return ret;88}8990/**91 * Frees memory allocated for the given queue. Node values are not freed92 * you have to free those manually using the address returned on dequeue.93 *94 * @pre The last element of the queue was already dequeued (queue is empty)95 * besides the given queue should not be NULL.96 * @param qu Queue for which allocated memory should be freed.97 */98void99freequeue(queue *qu)100{101 assert(qu);102103 if (sem_destroy(&qu->fullsem) || sem_destroy(&qu->emptysem))104 die("sem_destroy failed");105106 if ((errno = pthread_mutex_destroy(&qu->hmtx)) ||107 (errno = pthread_mutex_destroy(&qu->tmtx)))108 die("pthread_mutex_destroy failed");109110 free(qu);111}