mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / hidclass.sys / buffer.c
blobeccc3ed0c4e933f2206b0a4fe6c681a0506f26d0
1 /* Implementation of a ring buffer for reports
3 * Copyright 2015 CodeWeavers, Aric Stewart
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <stdarg.h>
21 #define NONAMELESSUNION
22 #include "hid.h"
24 #include "wine/debug.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(hid);
28 #define POINTER_UNUSED 0xffffffff
29 #define BASE_BUFFER_SIZE 32
30 #define MIN_BUFFER_SIZE 2
31 #define MAX_BUFFER_SIZE 512
33 struct ReportRingBuffer
35 UINT start, end, size;
37 UINT *pointers;
38 UINT pointer_alloc;
39 UINT buffer_size;
41 CRITICAL_SECTION lock;
43 BYTE *buffer;
46 struct ReportRingBuffer* RingBuffer_Create(UINT buffer_size)
48 struct ReportRingBuffer *ring;
49 int i;
51 TRACE("Create Ring Buffer with buffer size %i\n",buffer_size);
53 ring = HeapAlloc(GetProcessHeap(), 0, sizeof(*ring));
54 if (!ring)
55 return NULL;
56 ring->start = ring->end = 0;
57 ring->size = BASE_BUFFER_SIZE;
58 ring->buffer_size = buffer_size;
59 ring->pointer_alloc = 2;
60 ring->pointers = HeapAlloc(GetProcessHeap(), 0, sizeof(UINT) * ring->pointer_alloc);
61 if (!ring->pointers)
63 HeapFree(GetProcessHeap(), 0, ring);
64 return NULL;
66 for (i = 0; i < ring->pointer_alloc; i++)
67 ring->pointers[i] = POINTER_UNUSED;
68 ring->buffer = HeapAlloc(GetProcessHeap(), 0, buffer_size * ring->size);
69 if (!ring->buffer)
71 HeapFree(GetProcessHeap(), 0, ring->pointers);
72 HeapFree(GetProcessHeap(), 0, ring);
73 return NULL;
75 InitializeCriticalSection(&ring->lock);
76 ring->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": RingBuffer.lock");
77 return ring;
80 void RingBuffer_Destroy(struct ReportRingBuffer *ring)
82 HeapFree(GetProcessHeap(), 0, ring->buffer);
83 HeapFree(GetProcessHeap(), 0, ring->pointers);
84 ring->lock.DebugInfo->Spare[0] = 0;
85 DeleteCriticalSection(&ring->lock);
86 HeapFree(GetProcessHeap(), 0, ring);
89 UINT RingBuffer_GetBufferSize(struct ReportRingBuffer *ring)
91 return ring->buffer_size;
94 UINT RingBuffer_GetSize(struct ReportRingBuffer *ring)
96 return ring->size;
99 NTSTATUS RingBuffer_SetSize(struct ReportRingBuffer *ring, UINT size)
101 BYTE* new_buffer;
102 int i;
104 if (size < MIN_BUFFER_SIZE || size > MAX_BUFFER_SIZE)
105 return STATUS_INVALID_PARAMETER;
106 if (size == ring->size)
107 return STATUS_SUCCESS;
109 EnterCriticalSection(&ring->lock);
110 ring->start = ring->end = 0;
111 for (i = 0; i < ring->pointer_alloc; i++)
113 if (ring->pointers[i] != POINTER_UNUSED)
114 ring->pointers[i] = 0;
116 new_buffer = HeapAlloc(GetProcessHeap(), 0, ring->buffer_size * size);
117 if (!new_buffer)
119 LeaveCriticalSection(&ring->lock);
120 return STATUS_NO_MEMORY;
122 HeapFree(GetProcessHeap(), 0, ring->buffer);
123 ring->buffer = new_buffer;
124 ring->size = size;
125 LeaveCriticalSection(&ring->lock);
126 return STATUS_SUCCESS;
129 void RingBuffer_ReadNew(struct ReportRingBuffer *ring, UINT index, void *output, UINT *size)
131 void *ret = NULL;
133 EnterCriticalSection(&ring->lock);
134 if (index >= ring->pointer_alloc || ring->pointers[index] == POINTER_UNUSED)
136 LeaveCriticalSection(&ring->lock);
137 *size = 0;
138 return;
140 if (ring->pointers[index] == ring->end)
142 LeaveCriticalSection(&ring->lock);
143 *size = 0;
145 else
147 ret = &ring->buffer[ring->pointers[index] * ring->buffer_size];
148 memcpy(output, ret, ring->buffer_size);
149 ring->pointers[index]++;
150 if (ring->pointers[index] == ring->size)
151 ring->pointers[index] = 0;
152 LeaveCriticalSection(&ring->lock);
153 *size = ring->buffer_size;
157 void RingBuffer_Read(struct ReportRingBuffer *ring, UINT index, void *output, UINT *size)
159 int pointer;
160 void *ret = NULL;
162 EnterCriticalSection(&ring->lock);
163 if (index >= ring->pointer_alloc || ring->pointers[index] == POINTER_UNUSED
164 || ring->end == ring->start)
166 LeaveCriticalSection(&ring->lock);
167 *size = 0;
168 return;
171 pointer = ring->pointers[index];
173 if (pointer == ring->end)
174 pointer--;
176 if (pointer < 0)
177 pointer = ring->size - 1;
179 ret = &ring->buffer[pointer * ring->buffer_size];
180 memcpy(output, ret, ring->buffer_size);
181 if (pointer == ring->pointers[index])
183 ring->pointers[index]++;
184 if (ring->pointers[index] == ring->size)
185 ring->pointers[index] = 0;
187 LeaveCriticalSection(&ring->lock);
188 *size = ring->buffer_size;
191 UINT RingBuffer_AddPointer(struct ReportRingBuffer *ring)
193 UINT idx;
194 EnterCriticalSection(&ring->lock);
195 for (idx = 0; idx < ring->pointer_alloc; idx++)
196 if (ring->pointers[idx] == POINTER_UNUSED)
197 break;
198 if (idx >= ring->pointer_alloc)
200 int count = idx = ring->pointer_alloc;
201 ring->pointer_alloc *= 2;
202 ring->pointers = HeapReAlloc(GetProcessHeap(), 0, ring->pointers, sizeof(UINT) * ring->pointer_alloc);
203 for( ;count < ring->pointer_alloc; count++)
204 ring->pointers[count] = POINTER_UNUSED;
206 ring->pointers[idx] = ring->end;
207 LeaveCriticalSection(&ring->lock);
208 return idx;
211 void RingBuffer_RemovePointer(struct ReportRingBuffer *ring, UINT index)
213 EnterCriticalSection(&ring->lock);
214 if (index < ring->pointer_alloc)
215 ring->pointers[index] = POINTER_UNUSED;
216 LeaveCriticalSection(&ring->lock);
219 void RingBuffer_Write(struct ReportRingBuffer *ring, void *data)
221 UINT i;
223 EnterCriticalSection(&ring->lock);
224 memcpy(&ring->buffer[ring->end * ring->buffer_size], data, ring->buffer_size);
225 ring->end++;
226 if (ring->end == ring->size)
227 ring->end = 0;
228 if (ring->start == ring->end)
230 ring->start++;
231 if (ring->start == ring->size)
232 ring->start = 0;
234 for (i = 0; i < ring->pointer_alloc; i++)
235 if (ring->pointers[i] == ring->end)
236 ring->pointers[i] = ring->start;
237 LeaveCriticalSection(&ring->lock);