summaryrefslogtreecommitdiff
path: root/src/itc.c
blob: a1fde5253f0ca357c1bed380e75c7ead51bcf03c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#include "itc.h"

void itc_chan_create(itc_chan *chan)
{
	memset(chan, 0, sizeof(itc_chan));

	chan->mutex = SDL_CreateMutex();
	assert(chan->mutex);

	chan->sem = SDL_CreateSemaphore(0);
	assert(chan->sem);
}

void itc_chan_destroy(itc_chan *chan)
{
	// todo: free queue

	SDL_DestroySemaphore(chan->sem);
	SDL_DestroyMutex(chan->mutex);
}

void itc_chan_push(itc_chan *chan, int number, void *data)
{
	itc_message *msg;

	msg = calloc(1, sizeof(itc_message));
	assert(msg);

	msg->number = number;
	msg->data = data;

	SDL_LockMutex(chan->mutex);
	
	if (!chan->oldest) {      
		chan->oldest = msg;
		chan->newest = msg;
	} else {
		/*
		 *   head <---> ... <---> tail
		 *
		 */

		chan->newest->newer = msg;
		msg->older = chan->newest;
		chan->newest = msg;
	}

	SDL_SemPost(chan->sem);
	SDL_UnlockMutex(chan->mutex);
}

int itc_chan_pop(itc_chan *chan, int *number, void **data)
{
	itc_message *msg;

	SDL_LockMutex(chan->mutex);

	if (!chan->oldest) {
		SDL_UnlockMutex(chan->mutex);
		return 1;
	}

	msg = chan->oldest;

	if (msg->newer) {
		msg->newer->older = NULL;
		chan->oldest = msg->newer;
	} else {
		chan->newest = NULL;
		chan->oldest = NULL;
	}

	SDL_SemWait(chan->sem); // should be instant
	SDL_UnlockMutex(chan->mutex);

	*number = msg->number;
	*data = msg->data;
	free(msg);

	return 0;
}

int itc_chan_pop_block(itc_chan *chan, int *number, void **data)
{
	itc_message *msg;

	SDL_SemWait(chan->sem);
	SDL_LockMutex(chan->mutex);

	if (!chan->oldest) {
		SDL_UnlockMutex(chan->mutex);
		return 1;
	}

	msg = chan->oldest;

	if (msg->newer) {
		msg->newer->older = NULL;
		chan->oldest = msg->newer;
	} else {
		chan->newest = NULL;
		chan->oldest = NULL;
	}

	SDL_UnlockMutex(chan->mutex);

	*number = msg->number;
	*data = msg->data;
	free(msg);

	return 0;
}