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
21 #define NONAMELESSUNION
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
;
41 CRITICAL_SECTION lock
;
46 struct ReportRingBuffer
* RingBuffer_Create(UINT buffer_size
)
48 struct ReportRingBuffer
*ring
;
51 TRACE("Create Ring Buffer with buffer size %i\n",buffer_size
);
53 ring
= HeapAlloc(GetProcessHeap(), 0, sizeof(*ring
));
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
);
63 HeapFree(GetProcessHeap(), 0, ring
);
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
);
71 HeapFree(GetProcessHeap(), 0, ring
->pointers
);
72 HeapFree(GetProcessHeap(), 0, ring
);
75 InitializeCriticalSection(&ring
->lock
);
76 ring
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": RingBuffer.lock");
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
)
99 NTSTATUS
RingBuffer_SetSize(struct ReportRingBuffer
*ring
, UINT size
)
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
);
119 LeaveCriticalSection(&ring
->lock
);
120 return STATUS_NO_MEMORY
;
122 HeapFree(GetProcessHeap(), 0, ring
->buffer
);
123 ring
->buffer
= new_buffer
;
125 LeaveCriticalSection(&ring
->lock
);
126 return STATUS_SUCCESS
;
129 void RingBuffer_ReadNew(struct ReportRingBuffer
*ring
, UINT index
, void *output
, UINT
*size
)
133 EnterCriticalSection(&ring
->lock
);
134 if (index
>= ring
->pointer_alloc
|| ring
->pointers
[index
] == POINTER_UNUSED
)
136 LeaveCriticalSection(&ring
->lock
);
140 if (ring
->pointers
[index
] == ring
->end
)
142 LeaveCriticalSection(&ring
->lock
);
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
)
162 EnterCriticalSection(&ring
->lock
);
163 if (index
>= ring
->pointer_alloc
|| ring
->pointers
[index
] == POINTER_UNUSED
164 || ring
->end
== ring
->start
)
166 LeaveCriticalSection(&ring
->lock
);
171 pointer
= ring
->pointers
[index
];
173 if (pointer
== ring
->end
)
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
)
194 EnterCriticalSection(&ring
->lock
);
195 for (idx
= 0; idx
< ring
->pointer_alloc
; idx
++)
196 if (ring
->pointers
[idx
] == POINTER_UNUSED
)
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
);
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
)
223 EnterCriticalSection(&ring
->lock
);
224 memcpy(&ring
->buffer
[ring
->end
* ring
->buffer_size
], data
, ring
->buffer_size
);
226 if (ring
->end
== ring
->size
)
228 if (ring
->start
== ring
->end
)
231 if (ring
->start
== ring
->size
)
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
);