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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 91478aa was 1e2e0c1e, checked in by Lukas Mejdrech <lukasmejdrech@…>, 16 years ago
  • change in the pq_add interface
  • 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 int result;
232
233 // remove debug dump
234// printf( "packet %d released\n", packet->packet_id );
235 for( index = 0; ( index < FREE_QUEUES_COUNT - 1 ) && ( packet->length > ps_globals.sizes[ index ] ); ++ index );
236 result = pq_add( & ps_globals.free[ index ], packet, packet->length, packet->length );
237 assert( result == EOK );
238}
239
240packet_t packet_get( size_t addr_len, size_t max_prefix, size_t max_content, size_t max_suffix ){
241 int index;
242 packet_t packet;
243 size_t length;
244
245 length = ALIGN_UP( sizeof( struct packet ) + 2 * addr_len + max_prefix + max_content + max_suffix, PAGE_SIZE );
246 fibril_mutex_lock( & ps_globals.lock );
247 for( index = 0; index < FREE_QUEUES_COUNT - 1; ++ index ){
248 if( length <= ps_globals.sizes[ index ] ){
249 packet = ps_globals.free[ index ];
250 while( packet_is_valid( packet ) && ( packet->length < length )){
251 packet = pm_find( packet->next );
252 }
253 if( packet_is_valid( packet )){
254 if( packet == ps_globals.free[ index ] ){
255 ps_globals.free[ index ] = pq_detach( packet );
256 }else{
257 pq_detach( packet );
258 }
259 packet_init( packet, addr_len, max_prefix, max_content, max_suffix );
260 fibril_mutex_unlock( & ps_globals.lock );
261 // remove debug dump
262// printf( "packet %d got\n", packet->packet_id );
263 return packet;
264 }
265 }
266 }
267 packet = packet_create( length, addr_len, max_prefix, max_content, max_suffix );
268 fibril_mutex_unlock( & ps_globals.lock );
269 // remove debug dump
270// printf( "packet %d created\n", packet->packet_id );
271 return packet;
272}
273
274packet_t packet_create( size_t length, size_t addr_len, size_t max_prefix, size_t max_content, size_t max_suffix ){
275 ERROR_DECLARE;
276
277 packet_t packet;
278
279 // already locked
280 packet = ( packet_t ) mmap( NULL, length, PROTO_READ | PROTO_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0 );
281 if( packet == MAP_FAILED ) return NULL;
282 ++ ps_globals.count;
283 packet->packet_id = ps_globals.count;
284 packet->length = length;
285 packet_init( packet, addr_len, max_prefix, max_content, max_suffix );
286 packet->magic_value = PACKET_MAGIC_VALUE;
287 if( ERROR_OCCURRED( pm_add( packet ))){
288 munmap( packet, packet->length );
289 return NULL;
290 }
291 return packet;
292}
293
294void packet_init( packet_t packet, size_t addr_len, size_t max_prefix, size_t max_content, size_t max_suffix ){
295 // clear the packet content
296 bzero((( void * ) packet ) + sizeof( struct packet ), packet->length - sizeof( struct packet ));
297 // clear the packet header
298 packet->order = 0;
299 packet->metric = 0;
300 packet->previous = 0;
301 packet->next = 0;
302 packet->addr_len = 0;
303 packet->src_addr = sizeof( struct packet );
304 packet->dest_addr = packet->src_addr + addr_len;
305 packet->max_prefix = max_prefix;
306 packet->max_content = max_content;
307 packet->data_start = packet->dest_addr + addr_len + packet->max_prefix;
308 packet->data_end = packet->data_start;
309}
310
311int packet_reply( const packet_t packet ){
312 ipc_callid_t callid;
313 size_t size;
314
315 if( ! packet_is_valid( packet )) return EINVAL;
316 if( async_share_in_receive( & callid, & size ) <= 0 ) return EINVAL;
317 if( size != packet->length ) return ENOMEM;
318 return async_share_in_finalize( callid, packet, PROTO_READ | PROTO_WRITE );
319}
320
321/** @}
322 */
Note: See TracBrowser for help on using the repository browser.