tmsim

A fast turing machine simulator with graphviz export functionality

git clone https://git.8pit.net/tmsim.git

  1/*
  2 * Copyright © 2016-2019 Sören Tempel
  3 *
  4 * This program is free software: you can redistribute it and/or
  5 * modify it under the terms of the GNU Affero General Public
  6 * License as published by the Free Software Foundation, either
  7 * 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 of
 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 12 * Affero General Public License for more details.
 13 *
 14 * You should have received a copy of the GNU Affero General Public
 15 * License along with this program. If not, see
 16 * <http://www.gnu.org/licenses/>.
 17 */
 18
 19#include <assert.h>
 20#include <errno.h>
 21#include <pthread.h>
 22#include <semaphore.h>
 23#include <stdlib.h>
 24
 25#include "queue.h"
 26#include "token.h"
 27#include "util.h"
 28
 29/**
 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;
 38
 39	qu = emalloc(sizeof(queue));
 40	qu->head = qu->tail = 0;
 41
 42	if ((errno = pthread_mutex_init(&qu->hmtx, NULL)) ||
 43	    (errno = pthread_mutex_init(&qu->tmtx, NULL)))
 44		die("pthread_mutex_init failed");
 45
 46	if (sem_init(&qu->fullsem, 0, 0) ||
 47	    sem_init(&qu->emptysem, 0, NUMTOKENS))
 48		die("sem_init failed");
 49
 50	return qu;
 51}
 52
 53/**
 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 */
 60void
 61enqueue(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}
 69
 70/**
 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;
 80
 81	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);
 86
 87	return ret;
 88}
 89
 90/**
 91 * Frees memory allocated for the given queue. Node values are not freed
 92 * 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 */
 98void
 99freequeue(queue *qu)
100{
101	assert(qu);
102
103	if (sem_destroy(&qu->fullsem) || sem_destroy(&qu->emptysem))
104		die("sem_destroy failed");
105
106	if ((errno = pthread_mutex_destroy(&qu->hmtx)) ||
107	    (errno = pthread_mutex_destroy(&qu->tmtx)))
108		die("pthread_mutex_destroy failed");
109
110	free(qu);
111}