private.h: rename to contain dir
[platform/upstream/libwebsockets.git] / lib / misc / lwsac / lwsac.c
1 /*
2  * libwebsockets - lws alloc chunk
3  *
4  * Copyright (C) 2018 Andy Green <andy@warmcat.com>
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation:
9  *  version 2.1 of the License.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  *  MA  02110-1301  USA
20  */
21
22 #include "private-lib-core.h"
23 #include "private-lib-misc-lwsac.h"
24
25 void
26 lws_list_ptr_insert(lws_list_ptr *head, lws_list_ptr *add,
27                     lws_list_ptr_sort_func_t sort_func)
28 {
29         while (sort_func && *head) {
30                 if (sort_func(add, *head) <= 0)
31                         break;
32
33                 head = *head;
34         }
35
36         *add = *head;
37         *head = add;
38 }
39
40 size_t
41 lwsac_align(size_t length)
42 {
43         size_t align = sizeof(int *);
44
45         if (length & (align - 1))
46                 length += align - (length & (align - 1));
47
48         return length;
49 }
50
51 size_t
52 lwsac_sizeof(void)
53 {
54         return sizeof(struct lwsac);
55 }
56
57 size_t
58 lwsac_get_tail_pos(struct lwsac *lac)
59 {
60         return lac->ofs;
61 }
62
63 struct lwsac *
64 lwsac_get_next(struct lwsac *lac)
65 {
66         return lac->next;
67 }
68
69 void *
70 lwsac_use(struct lwsac **head, size_t ensure, size_t chunk_size)
71 {
72         struct lwsac *chunk;
73         size_t ofs, alloc;
74
75         /* ensure there's a chunk and enough space in it for this name */
76
77         if (!*head || (*head)->curr->alloc_size - (*head)->curr->ofs < ensure) {
78
79                 if (!chunk_size)
80                         alloc = LWSAC_CHUNK_SIZE + sizeof(*chunk);
81                 else
82                         alloc = chunk_size + sizeof(*chunk);
83
84                 /*
85                  * If we get asked for something outside our expectation,
86                  * allocate to meet it
87                  */
88
89                 if (ensure >= alloc - sizeof(*chunk))
90                         alloc = ensure + sizeof(*chunk);
91
92                 chunk = malloc(alloc);
93                 if (!chunk) {
94                         lwsl_err("%s: OOM trying to alloc %llud\n", __func__,
95                                         (unsigned long long)alloc);
96                         return NULL;
97                 }
98
99                 if (!*head) {
100                         *head = chunk;
101                         chunk->total_alloc_size = 0;
102                         chunk->total_blocks = 0;
103                 }
104                 else
105                         (*head)->curr->next = chunk;
106
107                 (*head)->curr = chunk;
108                 (*head)->curr->head = *head;
109
110                 chunk->next = NULL;
111                 chunk->alloc_size = alloc;
112                 chunk->detached = 0;
113                 chunk->refcount = 0;
114
115                 (*head)->total_alloc_size += alloc;
116                 (*head)->total_blocks++;
117
118                 /*
119                  * belabouring the point... ofs is aligned to the platform's
120                  * generic struct alignment at the start then
121                  */
122                 (*head)->curr->ofs = sizeof(*chunk);
123         }
124
125         ofs = (*head)->curr->ofs;
126
127         (*head)->curr->ofs += lwsac_align(ensure);
128         if ((*head)->curr->ofs >= (*head)->curr->alloc_size)
129                 (*head)->curr->ofs = (*head)->curr->alloc_size;
130
131         return (char *)(*head)->curr + ofs;
132 }
133
134 void *
135 lwsac_use_zero(struct lwsac **head, size_t ensure, size_t chunk_size)
136 {
137         void *p = lwsac_use(head, ensure, chunk_size);
138
139         if (p)
140                 memset(p, 0, ensure);
141
142         return p;
143 }
144
145 void *
146 lwsac_use_zeroed(struct lwsac **head, size_t ensure, size_t chunk_size)
147 {
148         void *r = lwsac_use(head, ensure, chunk_size);
149
150         if (r)
151                 memset(r, 0, ensure);
152
153         return r;
154 }
155
156 void
157 lwsac_free(struct lwsac **head)
158 {
159         struct lwsac *it = *head;
160
161         *head = NULL;
162         lwsl_debug("%s: head %p\n", __func__, *head);
163
164         while (it) {
165                 struct lwsac *tmp = it->next;
166
167                 free(it);
168                 it = tmp;
169         }
170 }
171
172 void
173 lwsac_info(struct lwsac *head)
174 {
175         if (!head)
176                 lwsl_debug("%s: empty\n", __func__);
177         else
178                 lwsl_debug("%s: lac %p: %dKiB in %d blocks\n", __func__, head,
179                    (int)(head->total_alloc_size >> 10), head->total_blocks);
180 }
181
182 uint64_t
183 lwsac_total_alloc(struct lwsac *head)
184 {
185         return head->total_alloc_size;
186 }
187
188 void
189 lwsac_reference(struct lwsac *head)
190 {
191         head->refcount++;
192         lwsl_debug("%s: head %p: (det %d) refcount -> %d\n",
193                     __func__, head, head->detached, head->refcount);
194 }
195
196 void
197 lwsac_unreference(struct lwsac **head)
198 {
199         if (!(*head))
200                 return;
201
202         if (!(*head)->refcount)
203                 lwsl_warn("%s: refcount going below zero\n", __func__);
204
205         (*head)->refcount--;
206
207         lwsl_debug("%s: head %p: (det %d) refcount -> %d\n",
208                     __func__, *head, (*head)->detached, (*head)->refcount);
209
210         if ((*head)->detached && !(*head)->refcount) {
211                 lwsl_debug("%s: head %p: FREED\n", __func__, *head);
212                 lwsac_free(head);
213         }
214 }
215
216 void
217 lwsac_detach(struct lwsac **head)
218 {
219         (*head)->detached = 1;
220         if (!(*head)->refcount) {
221                 lwsl_debug("%s: head %p: FREED\n", __func__, *head);
222                 lwsac_free(head);
223         } else
224                 lwsl_debug("%s: head %p: refcount %d: Marked as detached\n",
225                             __func__, *head, (*head)->refcount);
226 }