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
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
= malloc(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
= malloc(sizeof(UINT
) * ring
->pointer_alloc
);
66 for (i
= 0; i
< ring
->pointer_alloc
; i
++)
67 ring
->pointers
[i
] = POINTER_UNUSED
;
68 ring
->buffer
= malloc(buffer_size
* ring
->size
);
75 InitializeCriticalSection(&ring
->lock
);
76 ring
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": RingBuffer.lock");
80 void RingBuffer_Destroy(struct ReportRingBuffer
*ring
)
84 ring
->lock
.DebugInfo
->Spare
[0] = 0;
85 DeleteCriticalSection(&ring
->lock
);
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
= malloc(ring
->buffer_size
* size
);
119 LeaveCriticalSection(&ring
->lock
);
120 return STATUS_NO_MEMORY
;
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 UINT
RingBuffer_AddPointer(struct ReportRingBuffer
*ring
)
160 EnterCriticalSection(&ring
->lock
);
161 for (idx
= 0; idx
< ring
->pointer_alloc
; idx
++)
162 if (ring
->pointers
[idx
] == POINTER_UNUSED
)
164 if (idx
>= ring
->pointer_alloc
)
166 int count
= idx
= ring
->pointer_alloc
;
167 ring
->pointer_alloc
*= 2;
168 ring
->pointers
= realloc(ring
->pointers
, sizeof(UINT
) * ring
->pointer_alloc
);
169 for( ;count
< ring
->pointer_alloc
; count
++)
170 ring
->pointers
[count
] = POINTER_UNUSED
;
172 ring
->pointers
[idx
] = ring
->end
;
173 LeaveCriticalSection(&ring
->lock
);
177 void RingBuffer_RemovePointer(struct ReportRingBuffer
*ring
, UINT index
)
179 EnterCriticalSection(&ring
->lock
);
180 if (index
< ring
->pointer_alloc
)
181 ring
->pointers
[index
] = POINTER_UNUSED
;
182 LeaveCriticalSection(&ring
->lock
);
185 void RingBuffer_Write(struct ReportRingBuffer
*ring
, void *data
)
189 EnterCriticalSection(&ring
->lock
);
190 memcpy(&ring
->buffer
[ring
->end
* ring
->buffer_size
], data
, ring
->buffer_size
);
192 if (ring
->end
== ring
->size
)
194 if (ring
->start
== ring
->end
)
197 if (ring
->start
== ring
->size
)
200 for (i
= 0; i
< ring
->pointer_alloc
; i
++)
201 if (ring
->pointers
[i
] == ring
->end
)
202 ring
->pointers
[i
] = ring
->start
;
203 LeaveCriticalSection(&ring
->lock
);