source: mainline/uspace/srv/net/structures/packet/packet_server.c@ f1848d6

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f1848d6 was daecfed3, checked in by Lukas Mejdrech <lukas@…>, 16 years ago
  • packet server allocates more free space than requested for possible error notification
  • Property mode set to 100644
File size: 11.1 KB
Line 
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
29/** @addtogroup packet
30 * @{
31 */
32
33/** @file
34 * Packet server implementation.
35 */
36
37#include <align.h>
38#include <assert.h>
39#include <async.h>
40#include <errno.h>
41#include <fibril_synch.h>
42#include <unistd.h>
43
44#include <ipc/ipc.h>
45#include <sys/mman.h>
46
47#include "../../err.h"
48#include "../../messages.h"
49
50#include "packet.h"
51#include "packet_client.h"
52#include "packet_header.h"
53#include "packet_messages.h"
54#include "packet_server.h"
55
56#define FREE_QUEUES_COUNT 7
57
58/** The default address length reserved for new packets.
59 */
60#define DEFAULT_ADDR_LEN 32
61
62/** The default prefix reserved for new packets.
63 */
64#define DEFAULT_PREFIX 64
65
66/** The default suffix reserved for new packets.
67 */
68#define DEFAULT_SUFFIX 64
69
70/** Packet server global data.
71 */
72static struct{
73 /** Safety lock.
74 */
75 fibril_mutex_t lock;
76 /** Free packet queues.
77 */
78 packet_t free[ FREE_QUEUES_COUNT ];
79 /** Packet length upper bounds of the free packet queues.
80 * The maximal lengths of packets in each queue in the ascending order.
81 * The last queue is not limited.
82 */
83 size_t sizes[ FREE_QUEUES_COUNT ];
84 /** Total packets allocated.
85 */
86 unsigned int count;
87} ps_globals = {
88 .lock = {
89 .counter = 1,
90 .waiters = {
91 .prev = & ps_globals.lock.waiters,
92 .next = & ps_globals.lock.waiters,
93 }
94 },
95 .free = { NULL, NULL, NULL, NULL, NULL, NULL, NULL },
96 .sizes = { PAGE_SIZE, PAGE_SIZE * 2, PAGE_SIZE * 4, PAGE_SIZE * 8, PAGE_SIZE * 16, PAGE_SIZE * 32, PAGE_SIZE * 64 },
97 .count = 0
98};
99
100/** @name Packet server support functions
101 */
102/*@{*/
103
104/** Returns the packet of dimensions at least as given.
105 * Tries to reuse free packets first.
106 * Creates a&nbsp;new packet aligned to the memory page size if none available.
107 * Locks the global data during its processing.
108 * @param[in] addr_len The source and destination addresses maximal length in bytes.
109 * @param[in] max_prefix The maximal prefix length in bytes.
110 * @param[in] max_content The maximal content length in bytes.
111 * @param[in] max_suffix The maximal suffix length in bytes.
112 * @returns The packet of dimensions at least as given.
113 * @returns NULL if there is not enough memory left.
114 */
115packet_t packet_get( size_t addr_len, size_t max_prefix, size_t max_content, size_t max_suffix );
116
117/** Releases the packet queue.
118 * @param[in] packet_id The first packet identifier.
119 * @returns EOK on success.
120 * @returns ENOENT if there is no such packet.
121 */
122int packet_release_wrapper( packet_id_t packet_id );
123
124/** Releases the packet and returns it to the appropriate free packet queue.
125 * Should be used only when the global data are locked.
126 * @param[in] packet The packet to be released.
127 */
128void packet_release( packet_t packet );
129
130/** Creates a&nbsp;new packet of dimensions at least as given.
131 * Should be used only when the global data are locked.
132 * @param[in] length The total length of the packet, including the header, the addresses and the data of the packet.
133 * @param[in] addr_len The source and destination addresses maximal length in bytes.
134 * @param[in] max_prefix The maximal prefix length in bytes.
135 * @param[in] max_content The maximal content length in bytes.
136 * @param[in] max_suffix The maximal suffix length in bytes.
137 * @returns The packet of dimensions at least as given.
138 * @returns NULL if there is not enough memory left.
139 */
140packet_t packet_create( size_t length, size_t addr_len, size_t max_prefix, size_t max_content, size_t max_suffix );
141
142/** Clears and initializes the packet according to the given dimensions.
143 * @param[in] packet The packet to be initialized.
144 * @param[in] addr_len The source and destination addresses maximal length in bytes.
145 * @param[in] max_prefix The maximal prefix length in bytes.
146 * @param[in] max_content The maximal content length in bytes.
147 * @param[in] max_suffix The maximal suffix length in bytes.
148 */
149void packet_init( packet_t packet, size_t addr_len, size_t max_prefix, size_t max_content, size_t max_suffix );
150
151/** Shares the packet memory block.
152 * @param[in] packet The packet to be shared.
153 * @returns EOK on success.
154 * @returns EINVAL if the packet is not valid.
155 * @returns EINVAL if the calling module does not accept the memory.
156 * @returns ENOMEM if the desired and actual sizes differ.
157 * @returns Other error codes as defined for the async_share_in_finalize() function.
158 */
159int packet_reply( const packet_t packet );
160
161/*@}*/
162
163int packet_translate( int phone, packet_ref packet, packet_id_t packet_id ){
164 if( ! packet ) return EINVAL;
165 * packet = pm_find( packet_id );
166 return ( * packet ) ? EOK : ENOENT;
167}
168
169packet_t packet_get_4( int phone, size_t max_content, size_t addr_len, size_t max_prefix, size_t max_suffix ){
170 return packet_get( addr_len, max_prefix, max_content, max_suffix );
171}
172
173packet_t packet_get_1( int phone, size_t content ){
174 return packet_get( DEFAULT_ADDR_LEN, DEFAULT_PREFIX, content, DEFAULT_SUFFIX );
175}
176
177void pq_release( int phone, packet_id_t packet_id ){
178 ( void ) packet_release_wrapper( packet_id );
179}
180
181int packet_server_message( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count ){
182 packet_t packet;
183
184 * answer_count = 0;
185 switch( IPC_GET_METHOD( * call )){
186 case IPC_M_PHONE_HUNGUP:
187 return EOK;
188 case NET_PACKET_CREATE_1:
189 packet = packet_get( DEFAULT_ADDR_LEN, DEFAULT_PREFIX, IPC_GET_CONTENT( call ), DEFAULT_SUFFIX );
190 if( ! packet ) return ENOMEM;
191 * answer_count = 2;
192 IPC_SET_ARG1( * answer, packet->packet_id );
193 IPC_SET_ARG2( * answer, packet->length );
194 return EOK;
195 case NET_PACKET_CREATE_4:
196 packet = packet_get((( DEFAULT_ADDR_LEN < IPC_GET_ADDR_LEN( call )) ? IPC_GET_ADDR_LEN( call ) : DEFAULT_ADDR_LEN ), DEFAULT_PREFIX + IPC_GET_PREFIX( call ), IPC_GET_CONTENT( call ), DEFAULT_SUFFIX + IPC_GET_SUFFIX( call ));
197 if( ! packet ) return ENOMEM;
198 * answer_count = 2;
199 IPC_SET_ARG1( * answer, packet->packet_id );
200 IPC_SET_ARG2( * answer, packet->length );
201 return EOK;
202 case NET_PACKET_GET:
203 packet = pm_find( IPC_GET_ID( call ));
204 if( ! packet_is_valid( packet )) return ENOENT;
205 return packet_reply( packet );
206 case NET_PACKET_GET_SIZE:
207 packet = pm_find( IPC_GET_ID( call ));
208 if( ! packet_is_valid( packet )) return ENOENT;
209 IPC_SET_ARG1( * answer, packet->length );
210 * answer_count = 1;
211 return EOK;
212 case NET_PACKET_RELEASE:
213 return packet_release_wrapper( IPC_GET_ID( call ));
214 }
215 return ENOTSUP;
216}
217
218int packet_release_wrapper( packet_id_t packet_id ){
219 packet_t packet;
220
221 packet = pm_find( packet_id );
222 if( ! packet_is_valid( packet )) return ENOENT;
223 fibril_mutex_lock( & ps_globals.lock );
224 pq_destroy( packet, packet_release );
225 fibril_mutex_unlock( & ps_globals.lock );
226 return EOK;
227}
228
229void packet_release( packet_t packet ){
230 int index;
231
232 // remove debug dump
233// printf( "packet %d released\n", packet->packet_id );
234 for( index = 0; ( index < FREE_QUEUES_COUNT - 1 ) && ( packet->length > ps_globals.sizes[ index ] ); ++ index );
235 ps_globals.free[ index ] = pq_add( ps_globals.free[ index ], packet, packet->length, packet->length );
236 assert( ps_globals.free[ index ] );
237}
238
239packet_t packet_get( size_t addr_len, size_t max_prefix, size_t max_content, size_t max_suffix ){
240 int index;
241 packet_t packet;
242 size_t length;
243
244 length = ALIGN_UP( sizeof( struct packet ) + 2 * addr_len + max_prefix + max_content + max_suffix, PAGE_SIZE );
245 fibril_mutex_lock( & ps_globals.lock );
246 for( index = 0; index < FREE_QUEUES_COUNT - 1; ++ index ){
247 if( length <= ps_globals.sizes[ index ] ){
248 packet = ps_globals.free[ index ];
249 while( packet_is_valid( packet ) && ( packet->length < length )){
250 packet = pm_find( packet->next );
251 }
252 if( packet_is_valid( packet )){
253 if( packet == ps_globals.free[ index ] ){
254 ps_globals.free[ index ] = pq_detach( packet );
255 }else{
256 pq_detach( packet );
257 }
258 packet_init( packet, addr_len, max_prefix, max_content, max_suffix );
259 fibril_mutex_unlock( & ps_globals.lock );
260 // remove debug dump
261// printf( "packet %d got\n", packet->packet_id );
262 return packet;
263 }
264 }
265 }
266 packet = packet_create( length, addr_len, max_prefix, max_content, max_suffix );
267 fibril_mutex_unlock( & ps_globals.lock );
268 // remove debug dump
269// printf( "packet %d created\n", packet->packet_id );
270 return packet;
271}
272
273packet_t packet_create( size_t length, size_t addr_len, size_t max_prefix, size_t max_content, size_t max_suffix ){
274 ERROR_DECLARE;
275
276 packet_t packet;
277
278 // already locked
279 packet = ( packet_t ) mmap( NULL, length, PROTO_READ | PROTO_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0 );
280 if( packet == MAP_FAILED ) return NULL;
281 ++ ps_globals.count;
282 packet->packet_id = ps_globals.count;
283 packet->length = length;
284 packet_init( packet, addr_len, max_prefix, max_content, max_suffix );
285 packet->magic_value = PACKET_MAGIC_VALUE;
286 if( ERROR_OCCURRED( pm_add( packet ))){
287 munmap( packet, packet->length );
288 return NULL;
289 }
290 return packet;
291}
292
293void packet_init( packet_t packet, size_t addr_len, size_t max_prefix, size_t max_content, size_t max_suffix ){
294 // clear the packet content
295 bzero((( void * ) packet ) + sizeof( struct packet ), packet->length - sizeof( struct packet ));
296 // clear the packet header
297 packet->order = 0;
298 packet->metric = 0;
299 packet->previous = 0;
300 packet->next = 0;
301 packet->addr_len = 0;
302 packet->src_addr = sizeof( struct packet );
303 packet->dest_addr = packet->src_addr + addr_len;
304 packet->max_prefix = max_prefix;
305 packet->max_content = max_content;
306 packet->data_start = packet->dest_addr + addr_len + packet->max_prefix;
307 packet->data_end = packet->data_start;
308}
309
310int packet_reply( const packet_t packet ){
311 ipc_callid_t callid;
312 size_t size;
313
314 if( ! packet_is_valid( packet )) return EINVAL;
315 if( async_share_in_receive( & callid, & size ) <= 0 ) return EINVAL;
316 if( size != packet->length ) return ENOMEM;
317 return async_share_in_finalize( callid, packet, PROTO_READ | PROTO_WRITE );
318}
319
320/** @}
321 */
Note: See TracBrowser for help on using the repository browser.