1 /*
2 * Copyright © 2019, VideoLAN and dav1d authors
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
19 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include <SDL.h>
28 #include <assert.h>
29
30 #include "dp_fifo.h"
31
32 // FIFO structure
33 struct dp_fifo
34 {
35 SDL_mutex *lock;
36 SDL_cond *cond_change;
37 size_t capacity;
38 size_t count;
39 void **entries;
40 int push_wait;
41 int flush;
42 };
43
44
dp_fifo_create(size_t capacity)45 Dav1dPlayPtrFifo *dp_fifo_create(size_t capacity)
46 {
47 Dav1dPlayPtrFifo *fifo;
48
49 assert(capacity > 0);
50 if (capacity <= 0)
51 return NULL;
52
53 fifo = malloc(sizeof(*fifo));
54 if (fifo == NULL)
55 return NULL;
56
57 fifo->capacity = capacity;
58 fifo->count = 0;
59 fifo->push_wait = 0;
60 fifo->flush = 0;
61
62 fifo->lock = SDL_CreateMutex();
63 if (fifo->lock == NULL) {
64 free(fifo);
65 return NULL;
66 }
67 fifo->cond_change = SDL_CreateCond();
68 if (fifo->cond_change == NULL) {
69 SDL_DestroyMutex(fifo->lock);
70 free(fifo);
71 return NULL;
72 }
73
74 fifo->entries = calloc(capacity, sizeof(void*));
75 if (fifo->entries == NULL) {
76 dp_fifo_destroy(fifo);
77 return NULL;
78 }
79
80 return fifo;
81 }
82
83 // Destroy FIFO
dp_fifo_destroy(Dav1dPlayPtrFifo * fifo)84 void dp_fifo_destroy(Dav1dPlayPtrFifo *fifo)
85 {
86 assert(fifo->count == 0);
87 SDL_DestroyMutex(fifo->lock);
88 SDL_DestroyCond(fifo->cond_change);
89 free(fifo->entries);
90 free(fifo);
91 }
92
93 // Push to FIFO
dp_fifo_push(Dav1dPlayPtrFifo * fifo,void * element)94 void dp_fifo_push(Dav1dPlayPtrFifo *fifo, void *element)
95 {
96 SDL_LockMutex(fifo->lock);
97 while (fifo->count == fifo->capacity) {
98 fifo->push_wait = 1;
99 SDL_CondWait(fifo->cond_change, fifo->lock);
100 fifo->push_wait = 0;
101 if (fifo->flush) {
102 SDL_CondSignal(fifo->cond_change);
103 SDL_UnlockMutex(fifo->lock);
104 return;
105 }
106 }
107 fifo->entries[fifo->count++] = element;
108 if (fifo->count == 1)
109 SDL_CondSignal(fifo->cond_change);
110 SDL_UnlockMutex(fifo->lock);
111 }
112
113 // Helper that shifts the FIFO array
dp_fifo_array_shift(void ** arr,size_t len)114 static void *dp_fifo_array_shift(void **arr, size_t len)
115 {
116 void *shifted_element = arr[0];
117 for (size_t i = 1; i < len; ++i)
118 arr[i-1] = arr[i];
119 return shifted_element;
120 }
121
122 // Get item from FIFO
dp_fifo_shift(Dav1dPlayPtrFifo * fifo)123 void *dp_fifo_shift(Dav1dPlayPtrFifo *fifo)
124 {
125 SDL_LockMutex(fifo->lock);
126 while (fifo->count == 0)
127 SDL_CondWait(fifo->cond_change, fifo->lock);
128 void *res = dp_fifo_array_shift(fifo->entries, fifo->count--);
129 if (fifo->count == fifo->capacity - 1)
130 SDL_CondSignal(fifo->cond_change);
131 SDL_UnlockMutex(fifo->lock);
132 return res;
133 }
134
dp_fifo_flush(Dav1dPlayPtrFifo * fifo,void (* destroy_elem)(void *))135 void dp_fifo_flush(Dav1dPlayPtrFifo *fifo, void (*destroy_elem)(void *))
136 {
137 SDL_LockMutex(fifo->lock);
138 fifo->flush = 1;
139 if (fifo->push_wait) {
140 SDL_CondSignal(fifo->cond_change);
141 SDL_CondWait(fifo->cond_change, fifo->lock);
142 }
143 while (fifo->count)
144 destroy_elem(fifo->entries[--fifo->count]);
145 fifo->flush = 0;
146 SDL_UnlockMutex(fifo->lock);
147 }
148