Code

c57b09d66123ba338925103f34d634cb861a4589
[sysdb.git] / src / utils / channel.c
1 /*
2  * SysDB - src/utils/channel.c
3  * Copyright (C) 2013 Sebastian 'tokkee' Harl <sh@tokkee.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
28 #include "utils/channel.h"
30 #include <assert.h>
32 #include <stdlib.h>
33 #include <string.h>
35 #include <pthread.h>
37 /*
38  * private data types
39  */
41 struct sdb_channel {
42         pthread_mutex_t lock;
44         /* maybe TODO: add support for 'nil' values using a boolean area */
46         void  *data;
47         size_t data_len;
48         size_t elem_size;
50         size_t head;
51         size_t tail;
52         _Bool full;
53 };
55 /*
56  * private helper functions
57  */
59 #define NEXT_WRITE(chan) (((chan)->tail + 1) % (chan)->data_len)
60 #define NEXT_READ(chan) (((chan)->head + 1) % (chan)->data_len)
62 #define ELEM(chan, i) \
63         (void *)((char *)(chan)->data + (i) * (chan)->elem_size)
64 #define TAIL(chan) ELEM(chan, (chan)->tail)
65 #define HEAD(chan) ELEM(chan, (chan)->head)
67 /* Insert a new element at the end. */
68 static int
69 channel_write(sdb_channel_t *chan, const void *data)
70 {
71         assert(chan && data);
73         if (chan->full)
74                 return -1;
76         memcpy(TAIL(chan), data, chan->elem_size);
77         chan->tail = NEXT_WRITE(chan);
79         chan->full = chan->tail == chan->head;
80         return 0;
81 } /* channel_write */
83 /* retrieve the first element */
84 static int
85 channel_read(sdb_channel_t *chan, void *data)
86 {
87         assert(chan && data);
89         if ((chan->head == chan->tail) && (! chan->full))
90                 return -1;
92         memcpy(data, HEAD(chan), chan->elem_size);
93         chan->head = NEXT_READ(chan);
95         chan->full = 0;
96         return 0;
97 } /* channel_read */
99 /*
100  * public API
101  */
103 sdb_channel_t *
104 sdb_channel_create(size_t size, size_t elem_size)
106         sdb_channel_t *chan;
108         if (! elem_size)
109                 return NULL;
110         if (! size)
111                 size = 1;
113         chan = calloc(1, sizeof(*chan));
114         if (! chan)
115                 return NULL;
117         chan->data = calloc(size, elem_size);
118         if (! chan->data) {
119                 sdb_channel_destroy(chan);
120                 return NULL;
121         }
123         chan->data_len = size;
124         chan->elem_size = elem_size;
126         pthread_mutex_init(&chan->lock, /* attr = */ NULL);
128         chan->head = chan->tail = 0;
129         return chan;
130 } /* sdb_channel_create */
132 void
133 sdb_channel_destroy(sdb_channel_t *chan)
135         if (! chan)
136                 return;
138         pthread_mutex_lock(&chan->lock);
139         free(chan->data);
140         chan->data = NULL;
141         chan->data_len = 0;
143         pthread_mutex_unlock(&chan->lock);
144         pthread_mutex_destroy(&chan->lock);
145         free(chan);
146 } /* sdb_channel_destroy */
148 int
149 sdb_channel_write(sdb_channel_t *chan, const void *data)
151         int status;
153         if ((! chan) || (! data))
154                 return -1;
156         pthread_mutex_lock(&chan->lock);
157         status = channel_write(chan, data);
158         pthread_mutex_unlock(&chan->lock);
159         return status;
160 } /* sdb_channel_write */
162 int
163 sdb_channel_read(sdb_channel_t *chan, void *data)
165         int status;
167         if ((! chan) || (! data))
168                 return -1;
170         pthread_mutex_lock(&chan->lock);
171         status = channel_read(chan, data);
172         pthread_mutex_unlock(&chan->lock);
173         return status;
174 } /* sdb_channel_read */
176 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */