source: mainline/uspace/lib/packet/generic/packet_server.c@ 376a7fd

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 376a7fd was 376a7fd, checked in by Jakub Jermar <jakub@…>, 15 years ago

Free packets were still not searched for in the last free queue.

  • Property mode set to 100644
File size: 11.1 KB
RevLine 
[21580dd]1/*
2 * Copyright (c) 2009 Lukas Mejdrech
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
[515a00da]29/** @addtogroup libpacket
[21580dd]30 * @{
31 */
32
33/** @file
[515a00da]34 * Packet server implementation.
[21580dd]35 */
36
[515a00da]37#include <packet_server.h>
38#include <packet_local.h>
39
[21580dd]40#include <align.h>
41#include <assert.h>
42#include <async.h>
43#include <errno.h>
[c5b59ce]44#include <err.h>
[21580dd]45#include <fibril_synch.h>
46#include <unistd.h>
[d52fbaf]47#include <sys/mman.h>
[21580dd]48
49#include <ipc/ipc.h>
[d52fbaf]50#include <ipc/packet.h>
[514ee46]51#include <ipc/net.h>
52
[c69d327]53#include <net/packet.h>
54#include <net/packet_header.h>
[21580dd]55
56#define FREE_QUEUES_COUNT 7
57
[515a00da]58/** The default address length reserved for new packets. */
[21580dd]59#define DEFAULT_ADDR_LEN 32
60
[515a00da]61/** The default prefix reserved for new packets. */
[21580dd]62#define DEFAULT_PREFIX 64
63
[515a00da]64/** The default suffix reserved for new packets. */
[21580dd]65#define DEFAULT_SUFFIX 64
66
[515a00da]67/** Packet server global data. */
68static struct {
69 /** Safety lock. */
[21580dd]70 fibril_mutex_t lock;
[515a00da]71 /** Free packet queues. */
[aadf01e]72 packet_t free[FREE_QUEUES_COUNT];
[515a00da]73
74 /**
75 * Packet length upper bounds of the free packet queues. The maximal
76 * lengths of packets in each queue in the ascending order. The last
77 * queue is not limited.
[21580dd]78 */
[aadf01e]79 size_t sizes[FREE_QUEUES_COUNT];
[515a00da]80
81 /** Total packets allocated. */
[21580dd]82 unsigned int count;
83} ps_globals = {
[e721462]84 .lock = FIBRIL_MUTEX_INITIALIZER(ps_globals.lock),
[515a00da]85 .free = {
86 NULL,
87 NULL,
88 NULL,
89 NULL,
90 NULL,
91 NULL,
92 NULL
93 },
94 .sizes = {
95 PAGE_SIZE,
96 PAGE_SIZE * 2,
97 PAGE_SIZE * 4,
98 PAGE_SIZE * 8,
99 PAGE_SIZE * 16,
100 PAGE_SIZE * 32,
101 PAGE_SIZE * 64
102 },
[21580dd]103 .count = 0
104};
105
[14f1db0]106int packet_translate_local(int phone, packet_ref packet, packet_id_t packet_id)
107{
108 if (!packet)
[849ed54]109 return EINVAL;
[14f1db0]110
[849ed54]111 *packet = pm_find(packet_id);
112 return (*packet) ? EOK : ENOENT;
113}
[21580dd]114
[849ed54]115/** Clears and initializes the packet according to the given dimensions.
[515a00da]116 *
117 * @param[in] packet The packet to be initialized.
118 * @param[in] addr_len The source and destination addresses maximal length in
119 * bytes.
120 * @param[in] max_prefix The maximal prefix length in bytes.
121 * @param[in] max_content The maximal content length in bytes.
122 * @param[in] max_suffix The maximal suffix length in bytes.
[21580dd]123 */
[515a00da]124static void
125packet_init(packet_t packet, size_t addr_len, size_t max_prefix,
126 size_t max_content, size_t max_suffix)
127{
[849ed54]128 // clear the packet content
[515a00da]129 bzero(((void *) packet) + sizeof(struct packet),
130 packet->length - sizeof(struct packet));
131
[849ed54]132 // clear the packet header
133 packet->order = 0;
134 packet->metric = 0;
135 packet->previous = 0;
136 packet->next = 0;
137 packet->addr_len = 0;
138 packet->src_addr = sizeof(struct packet);
139 packet->dest_addr = packet->src_addr + addr_len;
140 packet->max_prefix = max_prefix;
141 packet->max_content = max_content;
142 packet->data_start = packet->dest_addr + addr_len + packet->max_prefix;
143 packet->data_end = packet->data_start;
144}
[21580dd]145
[515a00da]146/** Creates a new packet of dimensions at least as given.
147 *
148 * Should be used only when the global data are locked.
149 *
150 * @param[in] length The total length of the packet, including the header,
151 * the addresses and the data of the packet.
152 * @param[in] addr_len The source and destination addresses maximal length in
153 * bytes.
154 * @param[in] max_prefix The maximal prefix length in bytes.
155 * @param[in] max_content The maximal content length in bytes.
156 * @param[in] max_suffix The maximal suffix length in bytes.
157 * @returns The packet of dimensions at least as given.
158 * @returns NULL if there is not enough memory left.
[21580dd]159 */
[515a00da]160static packet_t
161packet_create(size_t length, size_t addr_len, size_t max_prefix,
162 size_t max_content, size_t max_suffix)
163{
[849ed54]164 ERROR_DECLARE;
[21580dd]165
[849ed54]166 packet_t packet;
167
168 // already locked
[515a00da]169 packet = (packet_t) mmap(NULL, length, PROTO_READ | PROTO_WRITE,
170 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
171 if (packet == MAP_FAILED)
[849ed54]172 return NULL;
[515a00da]173
[9880813f]174 ps_globals.count++;
[849ed54]175 packet->packet_id = ps_globals.count;
176 packet->length = length;
177 packet_init(packet, addr_len, max_prefix, max_content, max_suffix);
178 packet->magic_value = PACKET_MAGIC_VALUE;
[515a00da]179 if (ERROR_OCCURRED(pm_add(packet))) {
[849ed54]180 munmap(packet, packet->length);
181 return NULL;
182 }
[515a00da]183
[849ed54]184 return packet;
185}
186
[14f1db0]187/** Return the packet of dimensions at least as given.
188 *
189 * Try to reuse free packets first.
190 * Create a new packet aligned to the memory page size if none available.
191 * Lock the global data during its processing.
192 *
[515a00da]193 * @param[in] addr_len The source and destination addresses maximal length in
194 * bytes.
195 * @param[in] max_prefix The maximal prefix length in bytes.
[14f1db0]196 * @param[in] max_content The maximal content length in bytes.
[515a00da]197 * @param[in] max_suffix The maximal suffix length in bytes.
198 * @return The packet of dimensions at least as given.
199 * @return NULL if there is not enough memory left.
[21580dd]200 */
[515a00da]201static packet_t
202packet_get_local(size_t addr_len, size_t max_prefix, size_t max_content,
203 size_t max_suffix)
[14f1db0]204{
[515a00da]205 size_t length = ALIGN_UP(sizeof(struct packet) + 2 * addr_len +
206 max_prefix + max_content + max_suffix, PAGE_SIZE);
[14f1db0]207
[849ed54]208 fibril_mutex_lock(&ps_globals.lock);
[14f1db0]209
210 packet_t packet;
211 unsigned int index;
212
[279b80c]213 for (index = 0; index < FREE_QUEUES_COUNT; index++) {
[376a7fd]214 if ((length > ps_globals.sizes[index]) &&
215 (index < FREE_QUEUES_COUNT - 1))
[515a00da]216 continue;
217
218 packet = ps_globals.free[index];
219 while (packet_is_valid(packet) && (packet->length < length))
220 packet = pm_find(packet->next);
221
222 if (packet_is_valid(packet)) {
223 if (packet == ps_globals.free[index])
224 ps_globals.free[index] = pq_detach(packet);
225 else
226 pq_detach(packet);
[14f1db0]227
[515a00da]228 packet_init(packet, addr_len, max_prefix, max_content,
229 max_suffix);
230 fibril_mutex_unlock(&ps_globals.lock);
[14f1db0]231
[515a00da]232 return packet;
[849ed54]233 }
[aadf01e]234 }
[14f1db0]235
236 packet = packet_create(length, addr_len, max_prefix, max_content,
237 max_suffix);
238
[849ed54]239 fibril_mutex_unlock(&ps_globals.lock);
[14f1db0]240
[849ed54]241 return packet;
[21580dd]242}
243
[14f1db0]244packet_t packet_get_4_local(int phone, size_t max_content, size_t addr_len,
245 size_t max_prefix, size_t max_suffix)
246{
247 return packet_get_local(addr_len, max_prefix, max_content, max_suffix);
[21580dd]248}
249
[14f1db0]250packet_t packet_get_1_local(int phone, size_t content)
251{
252 return packet_get_local(DEFAULT_ADDR_LEN, DEFAULT_PREFIX, content,
253 DEFAULT_SUFFIX);
[21580dd]254}
255
[14f1db0]256/** Release the packet and returns it to the appropriate free packet queue.
257 *
[515a00da]258 * Should be used only when the global data are locked.
[14f1db0]259 *
[515a00da]260 * @param[in] packet The packet to be released.
[14f1db0]261 *
[849ed54]262 */
[515a00da]263static void packet_release(packet_t packet)
264{
[849ed54]265 int index;
266 int result;
267
[515a00da]268 for (index = 0; (index < FREE_QUEUES_COUNT - 1) &&
269 (packet->length > ps_globals.sizes[index]); index++) {
270 ;
271 }
272
273 result = pq_add(&ps_globals.free[index], packet, packet->length,
274 packet->length);
[849ed54]275 assert(result == EOK);
276}
277
278/** Releases the packet queue.
[515a00da]279 *
280 * @param[in] packet_id The first packet identifier.
281 * @returns EOK on success.
282 * @returns ENOENT if there is no such packet.
[849ed54]283 */
[515a00da]284static int packet_release_wrapper(packet_id_t packet_id)
285{
[849ed54]286 packet_t packet;
287
288 packet = pm_find(packet_id);
[515a00da]289 if (!packet_is_valid(packet))
[849ed54]290 return ENOENT;
[515a00da]291
[849ed54]292 fibril_mutex_lock(&ps_globals.lock);
293 pq_destroy(packet, packet_release);
294 fibril_mutex_unlock(&ps_globals.lock);
[515a00da]295
[849ed54]296 return EOK;
297}
298
[14f1db0]299void pq_release_local(int phone, packet_id_t packet_id)
300{
[aadf01e]301 (void) packet_release_wrapper(packet_id);
[21580dd]302}
303
[849ed54]304/** Shares the packet memory block.
[515a00da]305 * @param[in] packet The packet to be shared.
306 * @returns EOK on success.
307 * @returns EINVAL if the packet is not valid.
308 * @returns EINVAL if the calling module does not accept the memory.
309 * @returns ENOMEM if the desired and actual sizes differ.
310 * @returns Other error codes as defined for the
311 * async_share_in_finalize() function.
[849ed54]312 */
[515a00da]313static int packet_reply(const packet_t packet)
314{
[849ed54]315 ipc_callid_t callid;
316 size_t size;
317
[515a00da]318 if (!packet_is_valid(packet))
[849ed54]319 return EINVAL;
[515a00da]320
[57f737a]321 if (!async_share_in_receive(&callid, &size)) {
322 ipc_answer_0(callid, EINVAL);
[515a00da]323 return EINVAL;
[57f737a]324 }
[a649e73f]325
326 if (size != packet->length) {
327 ipc_answer_0(callid, ENOMEM);
328 return ENOMEM;
329 }
[515a00da]330
331 return async_share_in_finalize(callid, packet,
332 PROTO_READ | PROTO_WRITE);
[849ed54]333}
334
[515a00da]335/** Processes the packet server message.
336 *
337 * @param[in] callid The message identifier.
338 * @param[in] call The message parameters.
339 * @param[out] answer The message answer parameters.
340 * @param[out] answer_count The last parameter for the actual answer in the
341 * answer parameter.
342 * @returns EOK on success.
343 * @returns ENOMEM if there is not enough memory left.
344 * @returns ENOENT if there is no such packet as in the packet
345 * message parameter.
346 * @returns ENOTSUP if the message is not known.
347 * @returns Other error codes as defined for the
348 * packet_release_wrapper() function.
349 */
350int
351packet_server_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
352 int *answer_count)
353{
[21580dd]354 packet_t packet;
355
[aadf01e]356 *answer_count = 0;
[515a00da]357 switch (IPC_GET_METHOD(*call)) {
358 case IPC_M_PHONE_HUNGUP:
359 return EOK;
360
361 case NET_PACKET_CREATE_1:
362 packet = packet_get_local(DEFAULT_ADDR_LEN, DEFAULT_PREFIX,
363 IPC_GET_CONTENT(call), DEFAULT_SUFFIX);
364 if (!packet)
365 return ENOMEM;
366 *answer_count = 2;
367 IPC_SET_ARG1(*answer, (ipcarg_t) packet->packet_id);
368 IPC_SET_ARG2(*answer, (ipcarg_t) packet->length);
369 return EOK;
370
371 case NET_PACKET_CREATE_4:
372 packet = packet_get_local(
373 ((DEFAULT_ADDR_LEN < IPC_GET_ADDR_LEN(call)) ?
374 IPC_GET_ADDR_LEN(call) : DEFAULT_ADDR_LEN),
375 DEFAULT_PREFIX + IPC_GET_PREFIX(call),
376 IPC_GET_CONTENT(call),
377 DEFAULT_SUFFIX + IPC_GET_SUFFIX(call));
378 if (!packet)
379 return ENOMEM;
380 *answer_count = 2;
381 IPC_SET_ARG1(*answer, (ipcarg_t) packet->packet_id);
382 IPC_SET_ARG2(*answer, (ipcarg_t) packet->length);
383 return EOK;
384
385 case NET_PACKET_GET:
386 packet = pm_find(IPC_GET_ID(call));
387 if (!packet_is_valid(packet))
388 return ENOENT;
389 return packet_reply(packet);
390
391 case NET_PACKET_GET_SIZE:
392 packet = pm_find(IPC_GET_ID(call));
393 if (!packet_is_valid(packet))
394 return ENOENT;
395 IPC_SET_ARG1(*answer, (ipcarg_t) packet->length);
396 *answer_count = 1;
397 return EOK;
398
399 case NET_PACKET_RELEASE:
400 return packet_release_wrapper(IPC_GET_ID(call));
[21580dd]401 }
[515a00da]402
[21580dd]403 return ENOTSUP;
404}
405
406/** @}
407 */
Note: See TracBrowser for help on using the repository browser.