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
22 #define NONAMELESSUNION
25 #include "wine/debug.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(hid
);
29 #define POINTER_UNUSED 0xffffffff
30 #define BASE_BUFFER_SIZE 32
31 #define MIN_BUFFER_SIZE 2
32 #define MAX_BUFFER_SIZE 512
34 struct ReportRingBuffer
36 UINT start
, end
, size
;
42 CRITICAL_SECTION lock
;
47 struct ReportRingBuffer
* RingBuffer_Create(UINT buffer_size
)
49 struct ReportRingBuffer
*ring
;
52 TRACE("Create Ring Buffer with buffer size %i\n",buffer_size
);
54 ring
= HeapAlloc(GetProcessHeap(), 0, sizeof(*ring
));
57 ring
->start
= ring
->end
= 0;
58 ring
->size
= BASE_BUFFER_SIZE
;
59 ring
->buffer_size
= buffer_size
;
60 ring
->pointer_alloc
= 2;
61 ring
->pointers
= HeapAlloc(GetProcessHeap(), 0, sizeof(UINT
) * ring
->pointer_alloc
);
64 HeapFree(GetProcessHeap(), 0, ring
);
67 for (i
= 0; i
< ring
->pointer_alloc
; i
++)
68 ring
->pointers
[i
] = POINTER_UNUSED
;
69 ring
->buffer
= HeapAlloc(GetProcessHeap(), 0, buffer_size
* ring
->size
);
72 HeapFree(GetProcessHeap(), 0, ring
->pointers
);
73 HeapFree(GetProcessHeap(), 0, ring
);
76 InitializeCriticalSection(&ring
->lock
);
77 ring
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": RingBuffer.lock");
81 void RingBuffer_Destroy(struct ReportRingBuffer
*ring
)
83 HeapFree(GetProcessHeap(), 0, ring
->buffer
);
84 HeapFree(GetProcessHeap(), 0, ring
->pointers
);
85 ring
->lock
.DebugInfo
->Spare
[0] = 0;
86 DeleteCriticalSection(&ring
->lock
);
87 HeapFree(GetProcessHeap(), 0, ring
);
90 UINT
RingBuffer_GetBufferSize(struct ReportRingBuffer
*ring
)
92 return ring
->buffer_size
;
95 UINT
RingBuffer_GetSize(struct ReportRingBuffer
*ring
)
100 NTSTATUS
RingBuffer_SetSize(struct ReportRingBuffer
*ring
, UINT size
)
105 if (size
< MIN_BUFFER_SIZE
|| size
> MAX_BUFFER_SIZE
)
106 return STATUS_INVALID_PARAMETER
;
107 if (size
== ring
->size
)
108 return STATUS_SUCCESS
;
110 EnterCriticalSection(&ring
->lock
);
111 ring
->start
= ring
->end
= 0;
112 for (i
= 0; i
< ring
->pointer_alloc
; i
++)
114 if (ring
->pointers
[i
] != POINTER_UNUSED
)
115 ring
->pointers
[i
] = 0;
117 new_buffer
= HeapAlloc(GetProcessHeap(), 0, ring
->buffer_size
* size
);
120 LeaveCriticalSection(&ring
->lock
);
121 return STATUS_NO_MEMORY
;
123 HeapFree(GetProcessHeap(), 0, ring
->buffer
);
124 ring
->buffer
= new_buffer
;
126 LeaveCriticalSection(&ring
->lock
);
127 return STATUS_SUCCESS
;
130 void RingBuffer_ReadNew(struct ReportRingBuffer
*ring
, UINT index
, void *output
, UINT
*size
)
134 EnterCriticalSection(&ring
->lock
);
135 if (index
>= ring
->pointer_alloc
|| ring
->pointers
[index
] == POINTER_UNUSED
)
137 LeaveCriticalSection(&ring
->lock
);
141 if (ring
->pointers
[index
] == ring
->end
)
143 LeaveCriticalSection(&ring
->lock
);
148 ret
= &ring
->buffer
[ring
->pointers
[index
] * ring
->buffer_size
];
149 memcpy(output
, ret
, ring
->buffer_size
);
150 ring
->pointers
[index
]++;
151 if (ring
->pointers
[index
] == ring
->size
)
152 ring
->pointers
[index
] = 0;
153 LeaveCriticalSection(&ring
->lock
);
154 *size
= ring
->buffer_size
;
158 void RingBuffer_Read(struct ReportRingBuffer
*ring
, UINT index
, void *output
, UINT
*size
)
163 EnterCriticalSection(&ring
->lock
);
164 if (index
>= ring
->pointer_alloc
|| ring
->pointers
[index
] == POINTER_UNUSED
165 || ring
->end
== ring
->start
)
167 LeaveCriticalSection(&ring
->lock
);
172 pointer
= ring
->pointers
[index
];
174 if (pointer
== ring
->end
)
178 pointer
= ring
->size
- 1;
180 ret
= &ring
->buffer
[pointer
* ring
->buffer_size
];
181 memcpy(output
, ret
, ring
->buffer_size
);
182 if (pointer
== ring
->pointers
[index
])
184 ring
->pointers
[index
]++;
185 if (ring
->pointers
[index
] == ring
->size
)
186 ring
->pointers
[index
] = 0;
188 LeaveCriticalSection(&ring
->lock
);
189 *size
= ring
->buffer_size
;
192 UINT
RingBuffer_AddPointer(struct ReportRingBuffer
*ring
)
195 EnterCriticalSection(&ring
->lock
);
196 for (idx
= 0; idx
< ring
->pointer_alloc
; idx
++)
197 if (ring
->pointers
[idx
] == POINTER_UNUSED
)
199 if (idx
>= ring
->pointer_alloc
)
201 int count
= idx
= ring
->pointer_alloc
;
202 ring
->pointer_alloc
*= 2;
203 ring
->pointers
= HeapReAlloc(GetProcessHeap(), 0, ring
->pointers
, sizeof(UINT
) * ring
->pointer_alloc
);
204 for( ;count
< ring
->pointer_alloc
; count
++)
205 ring
->pointers
[count
] = POINTER_UNUSED
;
207 ring
->pointers
[idx
] = ring
->end
;
208 LeaveCriticalSection(&ring
->lock
);
212 void RingBuffer_RemovePointer(struct ReportRingBuffer
*ring
, UINT index
)
214 EnterCriticalSection(&ring
->lock
);
215 if (index
< ring
->pointer_alloc
)
216 ring
->pointers
[index
] = POINTER_UNUSED
;
217 LeaveCriticalSection(&ring
->lock
);
220 void RingBuffer_Write(struct ReportRingBuffer
*ring
, void *data
)
224 EnterCriticalSection(&ring
->lock
);
225 memcpy(&ring
->buffer
[ring
->end
* ring
->buffer_size
], data
, ring
->buffer_size
);
227 if (ring
->end
== ring
->size
)
229 if (ring
->start
== ring
->end
)
232 if (ring
->start
== ring
->size
)
235 for (i
= 0; i
< ring
->pointer_alloc
; i
++)
236 if (ring
->pointers
[i
] == ring
->end
)
237 ring
->pointers
[i
] = ring
->start
;
238 LeaveCriticalSection(&ring
->lock
);