xref: /xnu-12377.41.6/iokit/IOKit/IOCircularDataQueue.h (revision bbb1b6f9e71b8cdde6e5cd6f4841f207dee3d828)
1 /*
2  * Copyright (c) 2024 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 #ifndef IOGCCircularDataQueue_h
30 #define IOGCCircularDataQueue_h
31 
32 #if KERNEL
33 #include <IOKit/IOLib.h>
34 #else
35 #include <IOKit/IOKitLib.h>
36 #endif
37 
38 __BEGIN_DECLS
39 
40 struct IOCircularDataQueue;
41 typedef struct IOCircularDataQueue IOCircularDataQueue;
42 
43 // IOCircularDataQueueCreate* options
44 typedef enum __OS_ENUM_ATTR IOCircularDataQueueCreateOptions {
45 	kIOCircularDataQueueCreateConsumer = 0x00000001,
46 	kIOCircularDataQueueCreateProducer = 0x00000002
47 } IOCircularDataQueueCreateOptions;
48 
49 #if KERNEL
50 
51 /*!
52  * @function IOCircularDataQueueCreateWithEntries
53  * @abstract Function that creates a new IOCircularDataQueue instance with the specified number of entries of the given
54  * size.
55  * @discussion This method will create a new IOCircularDataQueue instance with enough capacity for numEntries of
56  * entrySize each.  It does account for the IOCircularDataQueueEntryHeader overhead for each entry.  Note that the
57  * numEntries and entrySize are simply used to determine the data region size.  They do not actually restrict the number
58  * of enqueues to the queue since its a circular buffer and will eventually overwrite old data. At any time, the
59  * allocated data region can hold a maximum of numEntries queue entries. <br>  This method allocates a new
60  * IOCircularDataQueue instance with the given numEntries and entrySize parameters.
61  * @param options IOCircularDataQueueCreateOptions.
62  * @param numEntries Number of entries to allocate space for.
63  * @param entrySize Size of each entry.
64  * @param pQueue Pointer to a queue handle. On return, this holds a handle to the newly allocated queue.
65  * @return
66  *  - `kIOReturnSuccess` if the queue was succesfully intialized.
67  *  - `kIOReturnBadArgument` if the parameters passed were invalid.
68  *  - `kIOReturnNoMemory` if there was a memory allocation failure.
69  */
70 IOReturn IOCircularDataQueueCreateWithEntries(IOCircularDataQueueCreateOptions options, uint32_t numEntries, uint32_t entrySize, IOCircularDataQueue **pQueue);
71 
72 /*!
73  * @function IOCircularDataQueueCopyMemoryDescriptor
74  * @abstract Returns a reference to the IOMemoryDescriptor for the queue's memory.
75  * @discussion Returns a reference to the IOMemoryDescriptor for the queue's memory.
76  * @param queue Queue handle. On return, this holds a handle to the newly allocated queue.
77  * @return IOMemoryDescriptor reference
78  */
79 IOMemoryDescriptor * IOCircularDataQueueCopyMemoryDescriptor(IOCircularDataQueue *queue);
80 
81 #else /* KERNEL */
82 
83 /*!
84  * @function IOCircularDataQueueCreateWithConnection
85  * @abstract Function that creates a new IOCircularDataQueue instance with an open IOUserClient connection.
86  * @discussion This method will create a new IOCircularDataQueue instance with a queue owned by the IOUserClient
87  * instance passed in. The memory and queue attributes are created from the IOMemoryDescriptor returned by the IOUC
88  * returned by clientMemoryForType() with the memoryType parameter passed to this function. This memory descriptor must
89  * be one returned by the kernel api IOCircularDataQueueCopyMemoryDescriptor().
90  * @param options IOCircularDataQueueCreateOptions.
91  * @param connect An open IOUserClient connection created by the caller with IOServiceOpen(). The connection must be
92  *        valid while the queue is in use.
93  * @param memoryType memoryType argument that will passed to the IOUC clientMemoryForType() function to obtain the queue memory.
94  * @param pQueue Pointer to a queue handle. On return, this holds a handle to the newly allocated queue.
95  * @return
96  *  - `kIOReturnSuccess` if the queue was succesfully intialized.
97  *  - `kIOReturnBadArgument` if the parameters passed were invalid.
98  *  - `kIOReturnNoMemory` if there was a memory allocation failure.
99  */
100 IOReturn IOCircularDataQueueCreateWithConnection(IOCircularDataQueueCreateOptions options, io_connect_t connect, uint32_t memoryType, IOCircularDataQueue **pQueue);
101 
102 #endif /* !KERNEL */
103 
104 /*!
105  * @function IOCircularDataQueueDestroy
106  * @abstract Function that destroys a previously created IOCircularDataQueue instance (created with
107  * IOCircularDataQueueCreateWithEntries).
108  * @param pQueue Pointer to the queue handle.
109  *  @return
110  *  - `kIOReturnSuccess` if the queue was succesfully destroyed.
111  *  - `kIOReturnBadArgument` if an invalid queue was provided.
112  */
113 IOReturn IOCircularDataQueueDestroy(IOCircularDataQueue **pQueue);
114 
115 
116 /*!
117  * @function IOCircularDataQueueEnqueue
118  * @abstract Enqueues a new entry on the queue.
119  * @discussion This method adds a new data entry of dataSize to the queue.  It sets the size parameter of the entry
120  * pointed to by the write index  and copies the memory pointed to by the data parameter in place in the queue.  Once
121  * that is done, it moves the write index to the next index.
122  * @param queue Handle to the queue.
123  * @param data Pointer to the data to be added to the queue.
124  * @param dataSize Size of the data pointed to by data.
125  *  @return
126  *  - `kIOReturnSuccess` on success.
127  *  - `kIOReturnBadMedia` if the queue shared memory has been compromised.
128  *  - `kIOReturnBadArgument` if an invalid queue was provided.
129  *  - `kIOReturnBusy` if another thread is enqueing concurrently
130  *  - `kIOReturnUnsupported` if the queue has not been configured to support fixed size entries. Variable size is
131  * currently not supported
132  *  - Other values indicate an error.
133  */
134 IOReturn IOCircularDataQueueEnqueue(IOCircularDataQueue *queue, const void *data, size_t dataSize);
135 
136 /*!
137  * @function IOCircularDataQueueGetLatest
138  * Access the latest entry data, also update the cursor position to the latest. No copy is made of the data. <br> Caller
139  * is supposed to call IOCircularDataQueueIsCurrentDataValid() to check data integrity after reading the data is
140  * complete.
141  * @param queue Handle to the queue.
142  * @param data A pointer to the data memory region for the latest entry data in the queue.
143  * @param size A pointer to the size of the data parameter.  On return, this contains the actual size of the data
144  * pointed to by data param.
145  *  @return
146  *  - `kIOReturnSuccess` if the cursor position was updated.
147  *  - `kIOReturnUnderrun` if nothing has ever been enqueued into the queue
148  *  - `kIOReturnBadMedia` if the queue shared memory has been compromised.
149  *  - `kIOReturnBadArgument` if an invalid queue was provided.
150  *  - `kIOReturnTimeout` if the reader timed out when trying to read. This is possible if the writer overwrites the
151  * latest index a reader is about to read. The function times out if the read is unsuccessful after multiple retries.
152  *  - Other values indicate an error.
153  */
154 IOReturn IOCircularDataQueueGetLatest(IOCircularDataQueue *queue, void **data, size_t *size);
155 
156 /*!
157  * @function IOCircularDataQueueCopyLatest
158  *  Access the latest entry data and copy into the provided buffer. Also update the cursor position to the latest. On a
159  * successful return, the function gaurantees that the latest data was successfully copied. In this case there is no
160  * need to call IOCircularDataQueueIsCurrentDataValid() after reading the data is complete, since the function returns a
161  * copy which cannot be overwritten by the writer.
162  * @param queue Handle to the queue.
163  * @param data Pointer to memory into which the latest data from the queue is copied. Lifetime of this memory is
164  * controlled by the caller.
165  * @param size Size of the data buffer provided for copying. On return, this contains the actual size of the data
166  * pointed to by data param.
167  *  @return
168  *  - `kIOReturnSuccess` if the cursor position was updated to latest and the data was successfully copied.
169  *  - `kIOReturnUnderrun` if nothing has ever been enqueued into the queue
170  *  - `kIOReturnBadArgument` if the buffer provided to copy the data is NULL or  if an invalid queue was provided..
171  *  - `kIOReturnBadMedia` if the queue shared memory has been compromised.
172  *  - `kIOReturnTimeout` if the reader timed out when trying to copy the latest data. This is possible if the writer
173  * overwrites the latest index a reader is about to copy. The function times out if the copy is unsuccessful after
174  * multiple retries.
175  *  - Other values indicate an error.
176  *
177  */
178 IOReturn IOCircularDataQueueCopyLatest(IOCircularDataQueue *queue, void *data, size_t *size);
179 
180 /*!
181  * @function IOCircularDataQueueGetNext
182  * Access the data at the next cursor position and updates the cursor position to the next. No copy is made of the data.
183  * <br> Caller is supposed to call IOCircularDataQueueIsCurrentDataValid() to check data integrity after reading the
184  * data is complete.
185  * @param queue Handle to the queue.
186  * @param data A pointer to the data memory region for the next entry data in the queue.
187  * @param size A pointer to the size of the data parameter.  On return, this contains the actual size of the data
188  * pointed to by data param.
189  *  @return
190  *  - `kIOReturnSuccess` if the cursor position was updated to the latest.
191  *  - `kIOReturnAborted` if the cursor has become invalid, possibly due to a reset of the queue.
192  *  - `kIOReturnUnderrun` if the cursor has reached the latest available data.
193  *  - `kIOReturnOverrun` if the entry at the cursor position is no longer in
194  *     the queue's buffer. Call IOCircularDataQueueGetLatest to get the latest data and cursor position.
195  *  - `kIOReturnBadArgument` if an invalid argument is passsed.
196  *  - `kIOReturnBadMedia` if the queue shared memory has been compromised.
197  *  - Other values indicate an error.
198  *
199  */
200 IOReturn IOCircularDataQueueGetNext(IOCircularDataQueue *queue, void **data, size_t *size);
201 
202 /*!
203  * @function IOCircularDataQueueCopyNext
204  * Access the data at the next cursor position and copy into the provided buffer. Also update the cursor position to the
205  * next. On a successful return, the function gaurantees that the next entry data was successfully copied. In this case
206  * there is no need to call IOCircularDataQueueIsCurrentDataValid() after reading the data is complete, since the
207  * function returns a copy which cannot be overwritten by the writer.
208  * @param queue Handle to the queue.
209  * @param data Pointer to memory into which the next data from the queue is copied. Lifetime of this memory is
210  * controlled by the caller.
211  * @param size Size of the data buffer provided for copying. On return, this contains the actual size of the data
212  * pointed to by data param.
213  *  @return
214  *  - `kIOReturnSuccess` if the cursor position was updated to next and the data was successfully copied.
215  *  - `kIOReturnAborted` if the cursor has become invalid, possibly due to a reset of the queue.
216  *  - `kIOReturnUnderrun` if the cursor has reached the latest available data.
217  *  - `kIOReturnOverrun` if the entry at the cursor position is no longer in
218  *     the queue's buffer. Call IOCircularDataQueueCopyLatest to get the latest data and cursor position.
219  *  - `kIOReturnBadArgument` if an invalid argument is passsed.
220  *  - `kIOReturnBadMedia` if the queue shared memory has been compromised.
221  *  - Other values indicate an error.
222  *
223  */
224 IOReturn IOCircularDataQueueCopyNext(IOCircularDataQueue *queue, void *data, size_t *size);
225 
226 /*!
227  * @function IOCircularDataQueueGetPrevious
228  * Access the data at the previous cursor position and updates the cursor position to the previous. No copy is made of
229  * the data. <br> Caller is supposed to call IOCircularDataQueueIsCurrentDataValid() to check data integrity after
230  * reading the data is complete.
231  * @param queue Handle to the queue.
232  * @param data A pointer to the data memory region for the previous entry data in the queue.
233  * @param size A pointer to the size of the data parameter.  On return, this contains the actual size of the data
234  * pointed to by data param.
235  *  @return
236  *  - `kIOReturnSuccess` if the cursor position was updated to the previous.
237  *  - `kIOReturnAborted` if the cursor has become invalid, possibly due to a reset of the queue.
238  *  - `kIOReturnOverrun` if the entry at the cursor position is no longer in
239  *     the queue's buffer. Call IOCircularDataQueueGetLatest to get the latest data and cursor position.
240  *  - `kIOReturnBadArgument` if an invalid argument is passsed.
241  *  - `kIOReturnBadMedia` if the queue shared memory has been compromised.
242  *  - Other values indicate an error.
243  *
244  */
245 IOReturn IOCircularDataQueueGetPrevious(IOCircularDataQueue *queue, void **data, size_t *size);
246 
247 /*!
248  * @function IOCircularDataQueueCopyPrevious
249  * Access the data at the previous cursor position and copy into the provided buffer. Also update the cursor position to
250  * the previous. On a successful return, the function gaurantees that the previous entry data was successfully copied.
251  * In this case there is no need to call IOCircularDataQueueIsCurrentDataValid() after reading the data is complete,
252  * since the function returns a copy which cannot be overwritten by the writer.
253  * @param queue Handle to the queue.
254  * @param data Pointer to memory into which the previous data is copied. Lifetime of this memory is controlled by the
255  * caller.
256  * @param size Size of the data buffer provided for copying. On return, this contains the actual size of the data
257  * pointed to by data param.
258  *  @return
259  *  - `kIOReturnSuccess` if the cursor position was updated to the previous and the data was successfully copied.
260  *  - `kIOReturnAborted` if the cursor has become invalid, possibly due to a reset of the queue.
261  *  - `kIOReturnOverrun` if the entry at the cursor position is no longer in
262  *     the queue's buffer. Call IOCircularDataQueueCopyLatest to get the latest data and cursor position.
263  *  - `kIOReturnBadArgument` if an invalid argument is passsed.
264  *  - `kIOReturnBadMedia` if the queue shared memory has been compromised.
265  *  - Other values indicate an error.
266  *
267  */
268 IOReturn IOCircularDataQueueCopyPrevious(IOCircularDataQueue *queue, void *data, size_t *size);
269 
270 /*!
271  * @function IOCircularDataQueueIsCurrentDataValid
272  * Verify if the data at the current cursor position is the same as the data when the cursor was first updated to this
273  * position. Call this function after having read the data at the current cursor position from the queue, since the
274  * queue entry could potentially have been overwritten by the writer while being read by the caller. <br>
275  * @param queue Handle to the queue.
276  *  @return
277  *  - `kIOReturnSuccess` if the data at the cursor position is unchanged.
278  *  - `kIOReturnOverrun` if the entry at the cursor position is no longer the same  and is
279  *     potentially overwritten. Call IOCircularDataQueueGetLatest to get the latest data and cursor position.
280  *  - `kIOReturnAborted` if the cursor has become invalid, possibly due to a reset of the queue.
281  *  - `kIOReturnBadArgument` if an invalid param was passed.
282  *  - `kIOReturnBadMedia` if the queueMemory is corrupted.
283  *  - Other values indicate an error.
284  *
285  */
286 IOReturn IOCircularDataQueueIsCurrentDataValid(IOCircularDataQueue *queue);
287 
288 /*!
289  * @function IOCircularDataQueueSetCursorLatest
290  * Set the current cursor position to the latest entry in the queue. This only updates the cursor and does not read the
291  * data from the queue. If nothing has been enqueued into the queue yet, this returns an error.
292  * @param queue Handle to the queue.
293  *  @return
294  *  - `kIOReturnSuccess` if the cursor position was updated to the latest.
295  *  - `kIOReturnUnderrun` if nothing has ever been enqueued into the queue since there is no latest entry.
296  *  - `kIOReturnAborted` if the queue is in an irrecoverable state.
297  *  - `kIOReturnBadArgument` if an invalid argument is passsed.
298  *  - `kIOReturnBadMedia` if the queue shared memory has been compromised.
299  *  - Other values indicate an error.
300  *
301  */
302 IOReturn IOCircularDataQueueSetCursorLatest(IOCircularDataQueue *queue);
303 
304 /*!
305  * @function IOCircularDataQueueGetCurrent
306  * Access the data at the current cursor position. The cursor position is unchanged. No copy is made of the data. <br>
307  * Caller is supposed to call IOCircularDataQueueIsCurrentDataValid() to check data integrity after reading the data is
308  * complete.
309  * @param queue Handle to the queue.
310  * @param data A pointer to the data memory region for the next entry data in the queue.
311  * @param size A pointer to the size of the data parameter.  On return, this contains the actual size of the data
312  * pointed to by data param.
313  *  @return
314  *  - `kIOReturnSuccess` if the cursor position was updated.
315  *  - `kIOReturnAborted` if the cursor has become invalid, possibly due to a reset of the queue.
316  *  - `kIOReturnUnderrun` if nothing has ever been enqueued into the queue hence there is no entry at the current
317  * position..
318  *  - `kIOReturnOverrun` if the entry at the current cursor position is no longer in
319  *     the queue's buffer. Call IOCircularDataQueueGetLatest to get the latest data and cursor position.
320  *  - `kIOReturnBadArgument` if an invalid argument is passsed.
321  *  - `kIOReturnBadMedia` if the queue shared memory has been compromised.
322  *  - Other values indicate an error.
323  *
324  */
325 IOReturn IOCircularDataQueueGetCurrent(IOCircularDataQueue *queue, void **data, size_t *size);
326 
327 /*!
328  * @function IOCircularDataQueueCopyCurrent
329  * Access the data at the current cursor position and copy into the provided buffer. The cursor position is unchanged.
330  * If successful, function gaurantees that the data returned is always valid, hence no need to call
331  * IOCircularDataQueueIsCurrentDataValid().
332  * @param queue Handle to the queue.
333  * @param data Pointer to memory into which the previous data is copied. Lifetime of this memory is controlled by the
334  * caller.
335  * @param size Size of the data buffer provided for copying. On return, this contains the actual size of the data
336  * pointed to by data param.
337  *  @return
338  *  - `kIOReturnSuccess` if the cursor position was updated.
339  *  - `kIOReturnAborted` if the cursor has become invalid, possibly due to a reset of the queue.
340  *  - `kIOReturnUnderrun` if nothing has ever been enqueued into the queue hence there is no entry at the current
341  * position..
342  *  - `kIOReturnOverrun` if the entry at the current cursor position is no longer in
343  *     the queue's buffer. Call IOCircularDataQueueCopyLatest to get the latest data and cursor position.
344  *  - `kIOReturnBadArgument` if an invalid argument is passsed.
345  *  - `kIOReturnBadMedia` if the queue shared memory has been compromised.
346  *  - Other values indicate an error.
347  *
348  */
349 IOReturn IOCircularDataQueueCopyCurrent(IOCircularDataQueue *queue, void *data, size_t *size);
350 
351 /*!
352  * @function IOCircularDataQueueGetLatestWithBlock
353  * Access the latest entry data, also update the cursor position to the latest. Calls the provided block with the data
354  * at the cursor position. No copy is made of the data. <br> Optionally the caller can call
355  * IOCircularDataQueueIsCurrentDataValid() to check data integrity after reading the data is complete in the block.
356  * Additionally the function also returns an error if the data has been overwritten after the block completion
357  * @param queue Handle to the queue.
358  * @param handler Block to call
359  * -param data Pointer to the latest data in the queue that the block is called with.
360  * -param size Size of the data pointed to by data that the block is called with.
361  * @return
362  *  - `kIOReturnSuccess` if the cursor position was updated to the latest.
363  *  - `kIOReturnUnderrun` if nothing has ever been enqueued into the queue
364  *  - `kIOReturnBadMedia` if the queue shared memory has been compromised.
365  *  - `kIOReturnBadArgument` if an invalid queue was provided.
366  *  - `kIOReturnAborted` if the queue was reset.
367  *  - Other values indicate an error.
368  *
369  */
370 IOReturn IOCircularDataQueueGetLatestWithBlock(IOCircularDataQueue * queue, void (^handler)(const void *data, size_t size));
371 
372 /*!
373  * @function IOCircularDataQueueGetNextWithBlock
374  * Access the data at the next cursor position and updates the cursor position to the next. Calls the provided block
375  * with the data at the cursor position. No copy is made of the data. <br> Optionally the caller can call
376  * IOCircularDataQueueIsCurrentDataValid() to check data integrity after reading the data is complete in the block.
377  * Additionally the function also returns an error if the data has been overwritten after the block completion.
378  * @param queue Handle to the queue.
379  * @param handler Block to call
380  * -param data A pointer to the data memory region for the next entry data in the queue that the block is called with.
381  * -param size Size of the data pointed to by data that the block is called with.
382  *  @return
383  *  - `kIOReturnSuccess` if the cursor position was updated to next.
384  *  - `kIOReturnAborted` if the cursor has become invalid, possibly due to a reset of the queue.
385  *  - `kIOReturnUnderrun` if the cursor has reached the latest available data.
386  *  - `kIOReturnOverrun` if the entry at the cursor position is no longer in
387  *     the queue's buffer. Call IOCircularDataQueueGetLatest to get the latest data and cursor position.
388  *  - `kIOReturnBadArgument` if an invalid argument is passsed.
389  *  - `kIOReturnBadMedia` if the queue shared memory has been compromised.
390  *  - Other values indicate an error.
391  *
392  */
393 IOReturn IOCircularDataQueueGetNextWithBlock(IOCircularDataQueue * queue, void (^handler)(const void *data, size_t size));
394 
395 /*!
396  * @function IOCircularDataQueueGetPreviousWithBlock
397  * Access the data at the previous cursor position and updates the cursor position to the previous. Calls the provided
398  * block with the data at the cursor position. No copy is made of the data. <br> Optionally the caller can call
399  * IOCircularDataQueueIsCurrentDataValid() to check data integrity after reading the data is complete in the block.
400  * Additionally the function also returns an error if the data has been overwritten after the block completion.
401  * @param queue Handle to the queue.
402  * @param handler Block to call
403  * -param data A pointer to the data memory region for the previous entry data in the queue that the block is called
404  * with.
405  * -param size Size of the data pointed to by data that the block is called with.
406  *  @return
407  *  - `kIOReturnSuccess` if the cursor position was updated to previous.
408  *  - `kIOReturnAborted` if the cursor has become invalid, possibly due to a reset of the queue.
409  *  - `kIOReturnUnderrun` if the entry at the cursor position is no longer in
410  *     the queue's buffer. Call IOCircularDataQueueGetLatest to get the latest data and cursor position.
411  *  - `kIOReturnBadArgument` if an invalid argument is passsed.
412  *  - `kIOReturnBadMedia` if the queue shared memory has been compromised.
413  *  - Other values indicate an error.
414  *
415  */
416 IOReturn IOCircularDataQueueGetPreviousWithBlock(IOCircularDataQueue * queue, void (^handler)(const void *data, size_t size));
417 
418 __END_DECLS
419 
420 #endif /* IOGCCircularDataQueue_h */
421