1 | /* |
2 | * libwebsockets - small server side websockets and web server implementation |
3 | * |
4 | * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com> |
5 | * |
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | * of this software and associated documentation files (the "Software"), to |
8 | * deal in the Software without restriction, including without limitation the |
9 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
10 | * sell copies of the Software, and to permit persons to whom the Software is |
11 | * furnished to do so, subject to the following conditions: |
12 | * |
13 | * The above copyright notice and this permission notice shall be included in |
14 | * all copies or substantial portions of the Software. |
15 | * |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
22 | * IN THE SOFTWARE. |
23 | */ |
24 | |
25 | /* |
26 | * lws_dsh (Disordered Shared Heap) is an opaque abstraction supporting a single |
27 | * linear buffer (overallocated at end of the lws_dsh_t) which may contain |
28 | * multiple kinds of packets that are retired out of order, and tracked by kind. |
29 | * |
30 | * Each kind of packet has an lws_dll2 list of its kind of packets and acts as |
31 | * a FIFO; packets of a particular type are always retired in order. But there |
32 | * is no requirement about the order types are retired matching the original |
33 | * order they arrived. |
34 | * |
35 | * Gaps are tracked as just another kind of "packet" list. |
36 | * |
37 | * "allocations" (including gaps) are prepended by an lws_dsh_object_t. |
38 | * |
39 | * dsh may themselves be on an lws_dll2_owner list, and under memory pressure |
40 | * allocate into other buffers on the list. |
41 | * |
42 | * All management structures exist inside the allocated buffer. |
43 | */ |
44 | |
45 | /** |
46 | * lws_dsh_create() - Allocate a DSH buffer |
47 | * |
48 | * \param owner: the owning list this dsh belongs on, or NULL if standalone |
49 | * \param buffer_size: the allocation in bytes |
50 | * \param count_kinds: how many separately-tracked fifos use the buffer |
51 | * |
52 | * This makes a single heap allocation that includes internal tracking objects |
53 | * in the buffer. Sub-allocated objects are bound to a "kind" index and |
54 | * managed via a FIFO for each kind. |
55 | * |
56 | * Every "kind" of allocation shares the same buffer space. |
57 | * |
58 | * Multiple buffers may be bound together in an lws_dll2 list, and if an |
59 | * allocation cannot be satisfied by the local buffer, space can be borrowed |
60 | * from other dsh in the same list (the local dsh FIFO tracks these "foreign" |
61 | * allocations as if they were local). |
62 | * |
63 | * Returns an opaque pointer to the dsh, or NULL if allocation failed. |
64 | */ |
65 | LWS_VISIBLE LWS_EXTERN struct lws_dsh * |
66 | lws_dsh_create(lws_dll2_owner_t *owner, size_t buffer_size, int count_kinds); |
67 | |
68 | /** |
69 | * lws_dsh_destroy() - Destroy a DSH buffer |
70 | * |
71 | * \param pdsh: pointer to the dsh pointer |
72 | * |
73 | * Deallocates the DSH and sets *pdsh to NULL. |
74 | * |
75 | * Before destruction, any foreign buffer usage on the part of this dsh are |
76 | * individually freed. All dsh on the same list are walked and checked if they |
77 | * have their own foreign allocations on the dsh buffer being destroyed. If so, |
78 | * it attempts to migrate the allocation to a dsh that is not currently being |
79 | * destroyed. If all else fails (basically the buffer memory is being shrunk) |
80 | * unmigratable objects are cleanly destroyed. |
81 | */ |
82 | LWS_VISIBLE LWS_EXTERN void |
83 | lws_dsh_destroy(struct lws_dsh **pdsh); |
84 | |
85 | /** |
86 | * lws_dsh_alloc_tail() - make a suballocation inside a dsh |
87 | * |
88 | * \param dsh: the dsh tracking the allocation |
89 | * \param kind: the kind of allocation |
90 | * \param src1: the first source data to copy |
91 | * \param size1: the size of the first source data |
92 | * \param src2: the second source data to copy (after the first), or NULL |
93 | * \param size2: the size of the second source data |
94 | * |
95 | * Allocates size1 + size2 bytes in a dsh (it prefers the given dsh but will |
96 | * borrow space from other dsh on the same list if necessary) and copies size1 |
97 | * bytes into it from src1, followed by size2 bytes from src2 if src2 isn't |
98 | * NULL. The actual suballocation is a bit larger because of alignment and a |
99 | * prepended management header. |
100 | * |
101 | * The suballocation is added to the kind-specific FIFO at the tail. |
102 | */ |
103 | LWS_VISIBLE LWS_EXTERN int |
104 | lws_dsh_alloc_tail(struct lws_dsh *dsh, int kind, const void *src1, |
105 | size_t size1, const void *src2, size_t size2); |
106 | |
107 | /** |
108 | * lws_dsh_free() - free a suballocation from the dsh |
109 | * |
110 | * \param obj: a pointer to a void * that pointed to the allocated payload |
111 | * |
112 | * This returns the space used by \p obj in the dsh buffer to the free list |
113 | * of the dsh the allocation came from. |
114 | */ |
115 | LWS_VISIBLE LWS_EXTERN void |
116 | lws_dsh_free(void **obj); |
117 | |
118 | LWS_VISIBLE LWS_EXTERN size_t |
119 | lws_dsh_get_size(struct lws_dsh *dsh, int kind); |
120 | |
121 | /** |
122 | * lws_dsh_get_head() - get the head allocation inside the dsh |
123 | * |
124 | * \param dsh: the dsh tracking the allocation |
125 | * \param kind: the kind of allocation |
126 | * \param obj: pointer to a void * to be set to the payload |
127 | * \param size: set to the size of the allocation |
128 | * |
129 | * This gets the "next" object in the kind FIFO for the dsh, and returns 0 if |
130 | * any. If none, returns nonzero. |
131 | * |
132 | * This is nondestructive of the fifo or the payload. Use lws_dsh_free on |
133 | * obj to remove the entry from the kind fifo and return the payload to the |
134 | * free list. |
135 | */ |
136 | LWS_VISIBLE LWS_EXTERN int |
137 | lws_dsh_get_head(struct lws_dsh *dsh, int kind, void **obj, size_t *size); |
138 | |
139 | /** |
140 | * lws_dsh_describe() - DEBUG BUILDS ONLY dump the dsh to the logs |
141 | * |
142 | * \param dsh: the dsh to dump |
143 | * \param desc: text that appears at the top of the dump |
144 | * |
145 | * Useful information for debugging lws_dsh |
146 | */ |
147 | LWS_VISIBLE LWS_EXTERN void |
148 | lws_dsh_describe(struct lws_dsh *dsh, const char *desc); |
149 | |