Skip to content

Commit 243b36a

Browse files
committed
Improve correctness of pipe
The bulk operations reduce critical section duration while maintaining proper task synchronization to prevent scheduler deadlocks in multi-task pipe communication scenarios.
1 parent 0892e41 commit 243b36a

File tree

2 files changed

+282
-45
lines changed

2 files changed

+282
-45
lines changed

include/sys/pipe.h

Lines changed: 96 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,116 @@
11
#pragma once
22

3+
/* Inter-task Communication Pipes
4+
*
5+
* Pipes provide a unidirectional FIFO communication channel between tasks.
6+
* They support both blocking and non-blocking I/O operations with automatic
7+
* buffer management using power-of-2 sizing for efficient masking operations.
8+
*/
9+
10+
#include <types.h>
11+
12+
/* Magic number for pipe validation and corruption detection */
13+
#define PIPE_MAGIC 0x50495045 /* "PIPE" */
14+
315
/* Pipe descriptor
416
*
5-
* The buffer size is forced to the next power-of-two so we can mask
6-
* the head/tail indices instead of performing expensive modulus.
17+
* The circular buffer uses head/tail indices with power-of-2 masking
18+
* for efficient wraparound. The 'used' counter provides O(1) empty/full
19+
* detection and accurate size reporting without head/tail comparison issues.
720
*/
821
typedef struct {
9-
char *buf; /* data buffer */
10-
uint16_t mask; /* capacity-1 (size is power of 2) */
11-
volatile uint16_t head; /* read index */
12-
volatile uint16_t tail; /* write index */
13-
volatile uint16_t used; /* bytes currently stored */
22+
char *buf; /* Data buffer (power-of-2 size) */
23+
uint16_t mask; /* Capacity - 1 */
24+
volatile uint16_t head; /* Read index (consumer position) */
25+
volatile uint16_t tail; /* Write index (producer position) */
26+
volatile uint16_t used; /* Bytes currently stored (0 to capacity) */
27+
uint32_t magic; /* Magic number for validation */
1428
} pipe_t;
1529

1630
/* Constructor / destructor */
31+
32+
/* Create a new pipe with specified buffer size.
33+
* @size: Desired buffer size (will be rounded up to next power-of-2)
34+
*
35+
* Returns Pointer to new pipe on success, NULL on failure
36+
* Note: Minimum size is 2 bytes, maximum is 32768 bytes
37+
*/
1738
pipe_t *mo_pipe_create(uint16_t size);
39+
40+
/* Destroy a pipe and free its resources.
41+
* @pipe: Pointer to pipe structure (NULL is safe no-op)
42+
*
43+
* Returns ERR_OK on success, ERR_FAIL if pipe is invalid
44+
*/
1845
int32_t mo_pipe_destroy(pipe_t *pipe);
1946

47+
/* Pipe operations */
48+
49+
/* Flush all data from the pipe (reset to empty state).
50+
* @pipe: Pointer to pipe structure (must be valid)
51+
*/
2052
void mo_pipe_flush(pipe_t *pipe);
21-
/* bytes currently in pipe */
53+
54+
/* Get the number of bytes currently stored in the pipe.
55+
* @pipe: Pointer to pipe structure
56+
*
57+
* Returns Number of bytes available for reading, or -1 if pipe is invalid
58+
*/
2259
int32_t mo_pipe_size(pipe_t *pipe);
2360

24-
/* Blocking I/O (runs in task context) */
61+
/* Get the total capacity of the pipe.
62+
* @pipe: Pointer to pipe structure
63+
*
64+
* Returns Total buffer size in bytes, or -1 if pipe is invalid
65+
*/
66+
int32_t mo_pipe_capacity(pipe_t *pipe);
67+
68+
/* Get the number of free bytes in the pipe.
69+
* @pipe: Pointer to pipe structure
70+
*
71+
* Returns Number of bytes available for writing, or -1 if pipe is invalid
72+
*/
73+
int32_t mo_pipe_free_space(pipe_t *pipe);
74+
75+
/* Blocking I/O (runs in task context only) */
76+
77+
/* Read data from pipe, blocking until all requested bytes are available.
78+
* @pipe: Pointer to pipe structure (must be valid)
79+
* @data: Buffer to store read data (must be non-NULL)
80+
* @size: Number of bytes to read (must be > 0)
81+
*
82+
* Returns Number of bytes read (equals size on success), negative on error
83+
*/
2584
int32_t mo_pipe_read(pipe_t *pipe, char *data, uint16_t size);
85+
86+
/* Write data to pipe, blocking until all data is written.
87+
* @pipe: Pointer to pipe structure (must be valid)
88+
* @data: Data to write (must be non-NULL)
89+
* @size: Number of bytes to write (must be > 0)
90+
*
91+
* Returns Number of bytes written (equals size on success), negative on error
92+
* Note: This function will block until all data can be written
93+
*/
2694
int32_t mo_pipe_write(pipe_t *pipe, const char *data, uint16_t size);
2795

28-
/* Non-blocking I/O (returns partial count on short read/write) */
96+
/* Non-blocking I/O (returns immediately with partial results) */
97+
98+
/* Read available data from pipe without blocking.
99+
* @pipe: Pointer to pipe structure (must be valid)
100+
* @data: Buffer to store read data (must be non-NULL)
101+
* @size: Maximum number of bytes to read
102+
*
103+
* Returnsd: Number of bytes actually read (0 to size), negative on error
104+
* Note: Returns immediately even if no data is available
105+
*/
29106
int32_t mo_pipe_nbread(pipe_t *pipe, char *data, uint16_t size);
107+
108+
/* Write data to pipe without blocking.
109+
* @pipe: Pointer to pipe structure (must be valid)
110+
* @data: Data to write (must be non-NULL)
111+
* @size: Number of bytes to write
112+
*
113+
* Returns Number of bytes actually written (0 to size), negative on error
114+
* Note: Returns immediately even if no space is available
115+
*/
30116
int32_t mo_pipe_nbwrite(pipe_t *pipe, const char *data, uint16_t size);

0 commit comments

Comments
 (0)