source: mainline/uspace/lib/packet/generic/packet_server.c@ 79ae36dd

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 79ae36dd was 79ae36dd, checked in by Martin Decky <martin@…>, 14 years ago

new async framework with integrated exchange tracking

  • strict isolation between low-level IPC and high-level async framework with integrated exchange tracking
    • each IPC connection is represented by an async_sess_t structure
    • each IPC exchange is represented by an async_exch_t structure
    • exchange management is either based on atomic messages (EXCHANGE_ATOMIC), locking (EXCHANGE_SERIALIZE) or connection cloning (EXCHANGE_CLONE)
  • async_obsolete: temporary compatibility layer to keep old async clients working (several pieces of code are currently broken, but only non-essential functionality)
  • IPC_M_PHONE_HANGUP is now method no. 0 (for elegant boolean evaluation)
  • IPC_M_DEBUG_ALL has been renamed to IPC_M_DEBUG
  • IPC_M_PING has been removed (VFS protocol now has VFS_IN_PING)
  • console routines in libc have been rewritten for better abstraction
  • additional use for libc-private header files (FILE structure opaque to the client)
  • various cstyle changes (typos, indentation, missing externs in header files, improved comments, etc.)
  • Property mode set to 100644
File size: 10.4 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
[21580dd]39#include <align.h>
40#include <assert.h>
41#include <async.h>
42#include <errno.h>
43#include <fibril_synch.h>
44#include <unistd.h>
[d52fbaf]45#include <sys/mman.h>
46#include <ipc/packet.h>
[514ee46]47#include <ipc/net.h>
[c69d327]48#include <net/packet.h>
49#include <net/packet_header.h>
[21580dd]50
51#define FREE_QUEUES_COUNT 7
52
[515a00da]53/** The default address length reserved for new packets. */
[21580dd]54#define DEFAULT_ADDR_LEN 32
55
[515a00da]56/** The default prefix reserved for new packets. */
[21580dd]57#define DEFAULT_PREFIX 64
58
[515a00da]59/** The default suffix reserved for new packets. */
[21580dd]60#define DEFAULT_SUFFIX 64
61
[515a00da]62/** Packet server global data. */
63static struct {
64 /** Safety lock. */
[21580dd]65 fibril_mutex_t lock;
[515a00da]66 /** Free packet queues. */
[46d4d9f]67 packet_t *free[FREE_QUEUES_COUNT];
[515a00da]68
69 /**
70 * Packet length upper bounds of the free packet queues. The maximal
71 * lengths of packets in each queue in the ascending order. The last
72 * queue is not limited.
[21580dd]73 */
[aadf01e]74 size_t sizes[FREE_QUEUES_COUNT];
[515a00da]75
76 /** Total packets allocated. */
[21580dd]77 unsigned int count;
78} ps_globals = {
[e721462]79 .lock = FIBRIL_MUTEX_INITIALIZER(ps_globals.lock),
[515a00da]80 .free = {
81 NULL,
82 NULL,
83 NULL,
84 NULL,
85 NULL,
86 NULL,
87 NULL
88 },
89 .sizes = {
90 PAGE_SIZE,
91 PAGE_SIZE * 2,
92 PAGE_SIZE * 4,
93 PAGE_SIZE * 8,
94 PAGE_SIZE * 16,
95 PAGE_SIZE * 32,
96 PAGE_SIZE * 64
97 },
[21580dd]98 .count = 0
99};
100
[849ed54]101/** Clears and initializes the packet according to the given dimensions.
[515a00da]102 *
103 * @param[in] packet The packet to be initialized.
104 * @param[in] addr_len The source and destination addresses maximal length in
105 * bytes.
106 * @param[in] max_prefix The maximal prefix length in bytes.
107 * @param[in] max_content The maximal content length in bytes.
108 * @param[in] max_suffix The maximal suffix length in bytes.
[21580dd]109 */
[515a00da]110static void
[46d4d9f]111packet_init(packet_t *packet, size_t addr_len, size_t max_prefix,
[515a00da]112 size_t max_content, size_t max_suffix)
113{
[28a3e74]114 /* Clear the packet content */
[46d4d9f]115 bzero(((void *) packet) + sizeof(packet_t),
116 packet->length - sizeof(packet_t));
[515a00da]117
[28a3e74]118 /* Clear the packet header */
[849ed54]119 packet->order = 0;
120 packet->metric = 0;
121 packet->previous = 0;
122 packet->next = 0;
123 packet->addr_len = 0;
[46d4d9f]124 packet->src_addr = sizeof(packet_t);
[849ed54]125 packet->dest_addr = packet->src_addr + addr_len;
126 packet->max_prefix = max_prefix;
127 packet->max_content = max_content;
128 packet->data_start = packet->dest_addr + addr_len + packet->max_prefix;
129 packet->data_end = packet->data_start;
130}
[21580dd]131
[515a00da]132/** Creates a new packet of dimensions at least as given.
133 *
134 * @param[in] length The total length of the packet, including the header,
135 * the addresses and the data of the packet.
136 * @param[in] addr_len The source and destination addresses maximal length in
137 * bytes.
138 * @param[in] max_prefix The maximal prefix length in bytes.
139 * @param[in] max_content The maximal content length in bytes.
140 * @param[in] max_suffix The maximal suffix length in bytes.
[1bfd3d3]141 * @return The packet of dimensions at least as given.
142 * @return NULL if there is not enough memory left.
[21580dd]143 */
[46d4d9f]144static packet_t *
[515a00da]145packet_create(size_t length, size_t addr_len, size_t max_prefix,
146 size_t max_content, size_t max_suffix)
147{
[46d4d9f]148 packet_t *packet;
[88b127b]149 int rc;
[849ed54]150
[01b87dc5]151 assert(fibril_mutex_is_locked(&ps_globals.lock));
152
[28a3e74]153 /* Already locked */
[46d4d9f]154 packet = (packet_t *) mmap(NULL, length, PROTO_READ | PROTO_WRITE,
[515a00da]155 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
156 if (packet == MAP_FAILED)
[849ed54]157 return NULL;
[515a00da]158
[9880813f]159 ps_globals.count++;
[849ed54]160 packet->packet_id = ps_globals.count;
161 packet->length = length;
162 packet_init(packet, addr_len, max_prefix, max_content, max_suffix);
163 packet->magic_value = PACKET_MAGIC_VALUE;
[88b127b]164 rc = pm_add(packet);
165 if (rc != EOK) {
[849ed54]166 munmap(packet, packet->length);
167 return NULL;
168 }
[515a00da]169
[849ed54]170 return packet;
171}
172
[14f1db0]173/** Return the packet of dimensions at least as given.
174 *
175 * Try to reuse free packets first.
176 * Create a new packet aligned to the memory page size if none available.
177 * Lock the global data during its processing.
178 *
[515a00da]179 * @param[in] addr_len The source and destination addresses maximal length in
180 * bytes.
181 * @param[in] max_prefix The maximal prefix length in bytes.
[14f1db0]182 * @param[in] max_content The maximal content length in bytes.
[515a00da]183 * @param[in] max_suffix The maximal suffix length in bytes.
184 * @return The packet of dimensions at least as given.
185 * @return NULL if there is not enough memory left.
[21580dd]186 */
[46d4d9f]187static packet_t *
[515a00da]188packet_get_local(size_t addr_len, size_t max_prefix, size_t max_content,
189 size_t max_suffix)
[14f1db0]190{
[46d4d9f]191 size_t length = ALIGN_UP(sizeof(packet_t) + 2 * addr_len +
[515a00da]192 max_prefix + max_content + max_suffix, PAGE_SIZE);
[14f1db0]193
[849ed54]194 fibril_mutex_lock(&ps_globals.lock);
[14f1db0]195
[46d4d9f]196 packet_t *packet;
[14f1db0]197 unsigned int index;
198
[279b80c]199 for (index = 0; index < FREE_QUEUES_COUNT; index++) {
[376a7fd]200 if ((length > ps_globals.sizes[index]) &&
201 (index < FREE_QUEUES_COUNT - 1))
[515a00da]202 continue;
203
204 packet = ps_globals.free[index];
205 while (packet_is_valid(packet) && (packet->length < length))
206 packet = pm_find(packet->next);
207
208 if (packet_is_valid(packet)) {
209 if (packet == ps_globals.free[index])
210 ps_globals.free[index] = pq_detach(packet);
211 else
212 pq_detach(packet);
[14f1db0]213
[515a00da]214 packet_init(packet, addr_len, max_prefix, max_content,
215 max_suffix);
216 fibril_mutex_unlock(&ps_globals.lock);
[14f1db0]217
[515a00da]218 return packet;
[849ed54]219 }
[aadf01e]220 }
[14f1db0]221
222 packet = packet_create(length, addr_len, max_prefix, max_content,
223 max_suffix);
224
[849ed54]225 fibril_mutex_unlock(&ps_globals.lock);
[14f1db0]226
[849ed54]227 return packet;
[21580dd]228}
229
[14f1db0]230/** Release the packet and returns it to the appropriate free packet queue.
231 *
[515a00da]232 * @param[in] packet The packet to be released.
[14f1db0]233 *
[849ed54]234 */
[46d4d9f]235static void packet_release(packet_t *packet)
[515a00da]236{
[849ed54]237 int index;
238 int result;
239
[01b87dc5]240 assert(fibril_mutex_is_locked(&ps_globals.lock));
241
[515a00da]242 for (index = 0; (index < FREE_QUEUES_COUNT - 1) &&
243 (packet->length > ps_globals.sizes[index]); index++) {
244 ;
245 }
246
247 result = pq_add(&ps_globals.free[index], packet, packet->length,
248 packet->length);
[849ed54]249 assert(result == EOK);
250}
251
252/** Releases the packet queue.
[515a00da]253 *
254 * @param[in] packet_id The first packet identifier.
[1bfd3d3]255 * @return EOK on success.
256 * @return ENOENT if there is no such packet.
[849ed54]257 */
[515a00da]258static int packet_release_wrapper(packet_id_t packet_id)
259{
[46d4d9f]260 packet_t *packet;
[849ed54]261
262 packet = pm_find(packet_id);
[515a00da]263 if (!packet_is_valid(packet))
[849ed54]264 return ENOENT;
[515a00da]265
[849ed54]266 fibril_mutex_lock(&ps_globals.lock);
267 pq_destroy(packet, packet_release);
268 fibril_mutex_unlock(&ps_globals.lock);
[515a00da]269
[849ed54]270 return EOK;
271}
272
273/** Shares the packet memory block.
[515a00da]274 * @param[in] packet The packet to be shared.
[1bfd3d3]275 * @return EOK on success.
276 * @return EINVAL if the packet is not valid.
277 * @return EINVAL if the calling module does not accept the memory.
278 * @return ENOMEM if the desired and actual sizes differ.
279 * @return Other error codes as defined for the
[515a00da]280 * async_share_in_finalize() function.
[849ed54]281 */
[46d4d9f]282static int packet_reply(packet_t *packet)
[515a00da]283{
[849ed54]284 ipc_callid_t callid;
285 size_t size;
286
[515a00da]287 if (!packet_is_valid(packet))
[849ed54]288 return EINVAL;
[515a00da]289
[57f737a]290 if (!async_share_in_receive(&callid, &size)) {
[ffa2c8ef]291 async_answer_0(callid, EINVAL);
[515a00da]292 return EINVAL;
[57f737a]293 }
[a649e73f]294
295 if (size != packet->length) {
[ffa2c8ef]296 async_answer_0(callid, ENOMEM);
[a649e73f]297 return ENOMEM;
298 }
[515a00da]299
300 return async_share_in_finalize(callid, packet,
301 PROTO_READ | PROTO_WRITE);
[849ed54]302}
303
[515a00da]304/** Processes the packet server message.
305 *
306 * @param[in] callid The message identifier.
307 * @param[in] call The message parameters.
308 * @param[out] answer The message answer parameters.
309 * @param[out] answer_count The last parameter for the actual answer in the
310 * answer parameter.
[1bfd3d3]311 * @return EOK on success.
312 * @return ENOMEM if there is not enough memory left.
313 * @return ENOENT if there is no such packet as in the packet
[515a00da]314 * message parameter.
[1bfd3d3]315 * @return ENOTSUP if the message is not known.
316 * @return Other error codes as defined for the
[515a00da]317 * packet_release_wrapper() function.
318 */
319int
320packet_server_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
[774e6d1a]321 size_t *answer_count)
[515a00da]322{
[46d4d9f]323 packet_t *packet;
[21580dd]324
[aadf01e]325 *answer_count = 0;
[79ae36dd]326
327 if (!IPC_GET_IMETHOD(*call))
[515a00da]328 return EOK;
329
[79ae36dd]330 switch (IPC_GET_IMETHOD(*call)) {
[515a00da]331 case NET_PACKET_CREATE_1:
332 packet = packet_get_local(DEFAULT_ADDR_LEN, DEFAULT_PREFIX,
[774e6d1a]333 IPC_GET_CONTENT(*call), DEFAULT_SUFFIX);
[515a00da]334 if (!packet)
335 return ENOMEM;
336 *answer_count = 2;
[96b02eb9]337 IPC_SET_ARG1(*answer, (sysarg_t) packet->packet_id);
338 IPC_SET_ARG2(*answer, (sysarg_t) packet->length);
[515a00da]339 return EOK;
340
341 case NET_PACKET_CREATE_4:
342 packet = packet_get_local(
[774e6d1a]343 ((DEFAULT_ADDR_LEN < IPC_GET_ADDR_LEN(*call)) ?
344 IPC_GET_ADDR_LEN(*call) : DEFAULT_ADDR_LEN),
345 DEFAULT_PREFIX + IPC_GET_PREFIX(*call),
346 IPC_GET_CONTENT(*call),
347 DEFAULT_SUFFIX + IPC_GET_SUFFIX(*call));
[515a00da]348 if (!packet)
349 return ENOMEM;
350 *answer_count = 2;
[96b02eb9]351 IPC_SET_ARG1(*answer, (sysarg_t) packet->packet_id);
352 IPC_SET_ARG2(*answer, (sysarg_t) packet->length);
[515a00da]353 return EOK;
354
355 case NET_PACKET_GET:
[774e6d1a]356 packet = pm_find(IPC_GET_ID(*call));
[515a00da]357 if (!packet_is_valid(packet))
358 return ENOENT;
359 return packet_reply(packet);
360
361 case NET_PACKET_GET_SIZE:
[774e6d1a]362 packet = pm_find(IPC_GET_ID(*call));
[515a00da]363 if (!packet_is_valid(packet))
364 return ENOENT;
[96b02eb9]365 IPC_SET_ARG1(*answer, (sysarg_t) packet->length);
[515a00da]366 *answer_count = 1;
367 return EOK;
368
369 case NET_PACKET_RELEASE:
[774e6d1a]370 return packet_release_wrapper(IPC_GET_ID(*call));
[21580dd]371 }
[515a00da]372
[21580dd]373 return ENOTSUP;
374}
375
376/** @}
377 */
Note: See TracBrowser for help on using the repository browser.