OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [net/] [lwip_tcpip/] [current/] [src/] [ecos/] [sys_arch.c] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      sys_arch.c
4
//
5
//      lwIP system architecture support.
6
//
7
//==========================================================================
8
//####ECOSGPLCOPYRIGHTBEGIN####
9
// -------------------------------------------
10
// This file is part of eCos, the Embedded Configurable Operating System.
11
// Copyright (C) 2008, 2009 Free Software Foundation
12
//
13
// eCos is free software; you can redistribute it and/or modify it under
14
// the terms of the GNU General Public License as published by the Free
15
// Software Foundation; either version 2 or (at your option) any later version.
16
//
17
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20
// for more details.
21
//
22
// You should have received a copy of the GNU General Public License along
23
// with eCos; if not, write to the Free Software Foundation, Inc.,
24
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25
//
26
// As a special exception, if other files instantiate templates or use macros
27
// or inline functions from this file, or you compile this file and link it
28
// with other works to produce a work based on this file, this file does not
29
// by itself cause the resulting work to be covered by the GNU General Public
30
// License. However the source code for this file must still be made available
31
// in accordance with section (3) of the GNU General Public License.
32
//
33
// This exception does not invalidate any other reasons why a work based on
34
// this file might be covered by the GNU General Public License.
35
// -------------------------------------------
36
//####ECOSGPLCOPYRIGHTEND####
37
//==========================================================================
38
//#####DESCRIPTIONBEGIN####
39
//
40
// Author(s):    Simon Kallweit
41
// Contributors:
42
// Date:         2008-12-02
43
// Purpose:
44
// Description:  Provides the system architecture support for lwIP.
45
//
46
//####DESCRIPTIONEND####
47
//
48
//==========================================================================
49
 
50
#include <pkgconf/hal.h>
51
 
52
#include <cyg/hal/hal_arch.h>
53
#include <cyg/kernel/kapi.h>
54
 
55
#include <lwip.h>
56
 
57
#include "lwip/opt.h"
58
#include "arch/sys_arch.h"
59
#include "lwip/sys.h"
60
#include "lwip/def.h"
61
#include "lwip/stats.h"
62
#include "lwip/debug.h"
63
 
64
// Milliseconds per system tick
65
#define MS_PER_TICK ((u32_t) (CYGNUM_HAL_RTC_NUMERATOR / \
66
                     (CYGNUM_HAL_RTC_DENOMINATOR * 1000000LL)))
67
 
68
// Macros to convert between ticks and milliseconds
69
#define TICKS_TO_MS(_ticks_)    ((u16_t) ((_ticks_) * MS_PER_TICK + 1))
70
#define MS_TO_TICKS(_ms_)       ((cyg_tick_count_t) (((_ms_) + \
71
                                 (MS_PER_TICK - 1)) / MS_PER_TICK))
72
 
73
#if !NO_SYS
74
 
75
// Thread structure
76
struct lwip_thread {
77
    struct lwip_thread *next;  // Next thread in linked list
78
    struct sys_timeouts to;    // List of timeouts
79
    cyg_handle_t handle;       // Thread handle
80
    cyg_thread thread;         // Thread store
81
};
82
 
83
// A var memory pool is used for allocating semaphores, mboxes and threads
84
static char var_data[CYGNUM_LWIP_VARMEMPOOL_SIZE];
85
static cyg_mempool_var var_mempool;
86
static cyg_handle_t var_handle;
87
 
88
// Internal lwip thread stacks are statically allocated
89
#define TOTAL_STACKSIZE     (TCPIP_THREAD_STACKSIZE +       \
90
                             SLIPIF_THREAD_STACKSIZE +      \
91
                             PPP_THREAD_STACKSIZE +         \
92
                             ETH_THREAD_STACKSIZE)
93
 
94
static cyg_mutex_t stack_mutex;
95
static char stack_data[TOTAL_STACKSIZE];
96
static char *stack_pos = stack_data;
97
 
98
// Timeout for threads which were not created by sys_thread_new()
99
static struct sys_timeouts to;
100
 
101
// List of threads
102
static struct lwip_thread *threads;
103
 
104
//
105
// Is called to initialize the sys_arch layer.
106
//
107
void
108
sys_init(void)
109
{
110
    cyg_mempool_var_create(
111
            var_data,
112
            sizeof(var_data),
113
            &var_handle,
114
            &var_mempool
115
        );
116
 
117
        threads = NULL;
118
        to.next = NULL;
119
 
120
        cyg_mutex_init(&stack_mutex);
121
}
122
 
123
//
124
// Creates and returns a new semaphore. The "count" argument specifies the
125
// initial state of the semaphore.
126
//
127
sys_sem_t
128
sys_sem_new(u8_t count)
129
{
130
    sys_sem_t sem;
131
 
132
    // Allocate semaphore
133
    sem = (cyg_sem_t *) cyg_mempool_var_try_alloc(var_handle, sizeof(cyg_sem_t));
134
    if (!sem)
135
        return SYS_SEM_NULL;
136
    cyg_semaphore_init(sem, count);
137
 
138
#if SYS_STATS
139
    lwip_stats.sys.sem.used++;
140
    if (lwip_stats.sys.sem.used > lwip_stats.sys.sem.max)
141
        lwip_stats.sys.sem.max = lwip_stats.sys.sem.used;
142
#endif
143
 
144
    return sem;
145
}
146
 
147
//
148
// Deallocates a semaphore.
149
//
150
void
151
sys_sem_free(sys_sem_t sem)
152
{
153
    if (!sem)
154
        return;
155
 
156
    cyg_semaphore_destroy(sem);
157
    cyg_mempool_var_free(var_handle, (void *) sem);
158
 
159
#if SYS_STATS
160
    lwip_stats.sys.sem.used--;
161
#endif
162
}
163
 
164
//
165
// Signals a semaphore.
166
//
167
void
168
sys_sem_signal(sys_sem_t sem)
169
{
170
    cyg_semaphore_post(sem);
171
}
172
 
173
//
174
// Blocks the thread while waiting for the semaphore to be signaled. If the
175
// "timeout" argument is non-zero, the thread should only be blocked for the
176
// specified time (measured in milliseconds). If the "timeout" argument is
177
// zero, the thread should be blocked until the semaphore is signalled.
178
//
179
// If the timeout argument is non-zero, the return value is the number of
180
// milliseconds spent waiting for the semaphore to be signaled. If the
181
// semaphore wasn't signaled within the specified time, the return value is
182
// SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
183
// (i.e., it was already signaled), the function may return zero.
184
//
185
// Notice that lwIP implements a function with a similar name, sys_sem_wait(),
186
// that uses the sys_arch_sem_wait() function.
187
//
188
u32_t
189
sys_arch_sem_wait(sys_sem_t sem, u32_t timeout)
190
{
191
    if (timeout) {
192
        cyg_tick_count_t start_time = cyg_current_time();
193
 
194
        // Wait for semaphore with timeout
195
        if (!cyg_semaphore_timed_wait(sem, start_time + MS_TO_TICKS(timeout)))
196
            return SYS_ARCH_TIMEOUT;
197
        // Return elapsed time
198
        return TICKS_TO_MS(cyg_current_time() - start_time);
199
    } else {
200
        // Wait for semaphore indefinitely
201
        cyg_semaphore_wait(sem);
202
        return 0;
203
    }
204
}
205
 
206
//
207
// Creates an empty mailbox for maximum "size" elements. Elements stored in
208
// mailboxes are pointers. You have to define macros "_MBOX_SIZE" in your
209
// lwipopts.h, or ignore this parameter in your implementation and use a
210
// default size.
211
//
212
sys_mbox_t
213
sys_mbox_new(int size)
214
{
215
        cyg_mbox *mbox;
216
        cyg_handle_t handle;
217
 
218
    LWIP_UNUSED_ARG(size);
219
 
220
        mbox = (cyg_mbox *) cyg_mempool_var_try_alloc(var_handle, sizeof(cyg_mbox));
221
        if (!mbox)
222
            return SYS_MBOX_NULL;
223
        cyg_mbox_create(&handle, mbox);
224
 
225
#if SYS_STATS
226
    lwip_stats.sys.mbox.used++;
227
    if (lwip_stats.sys.mbox.used > lwip_stats.sys.mbox.max)
228
        lwip_stats.sys.mbox.max = lwip_stats.sys.mbox.used;
229
#endif
230
 
231
        return handle;
232
}
233
 
234
//
235
// Deallocates a mailbox. If there are messages still present in the mailbox
236
// when the mailbox is deallocated, it is an indication of a programming error
237
// in lwIP and the developer should be notified.
238
//
239
void
240
sys_mbox_free(sys_mbox_t mbox)
241
{
242
    if (!mbox)
243
        return;
244
 
245
    if (cyg_mbox_peek(mbox))
246
        LWIP_DEBUGF(SYS_DEBUG | LWIP_DBG_LEVEL_WARNING,
247
                    ("sys_mbox_free: mbox not empty\n"));
248
 
249
        cyg_mbox_delete(mbox);
250
        cyg_mempool_var_free(var_handle, (void *) mbox);
251
 
252
#if SYS_STATS
253
    lwip_stats.sys.mbox.used--;
254
#endif
255
}
256
 
257
//
258
// cyg_mbox_put() should not be passed a NULL, otherwise the cyg_mbox_get()
259
// will not know if it's real data or an error condition. But lwIP does pass
260
// NULL on occasion, in cases when maybe using a semaphore would be better. So
261
// this null_msg replaces NULL data.
262
//
263
static int null_msg;
264
 
265
//
266
// Posts the "msg" to the mailbox. This function have to block until the "msg"
267
// is really posted.
268
//
269
void
270
sys_mbox_post(sys_mbox_t mbox, void *msg)
271
{
272
    // Map NULL messages
273
    if (!msg)
274
        msg = &null_msg;
275
    while (cyg_mbox_put(mbox, msg) == false);
276
}
277
 
278
//
279
// Try to post the "msg" to the mailbox. Returns ERR_MEM if this one is full,
280
// else, ERR_OK if the "msg" is posted.
281
//
282
err_t
283
sys_mbox_trypost(sys_mbox_t mbox, void *msg)
284
{
285
    // Map NULL messages
286
    if (!msg)
287
        msg = &null_msg;
288
    return cyg_mbox_tryput(mbox, msg) ? ERR_OK : ERR_MEM;
289
}
290
 
291
//
292
// Blocks the thread until a message arrives in the mailbox, but does not block
293
// the thread longer than "timeout" milliseconds (similar to the
294
// sys_arch_sem_wait() function). If "timeout" is 0, the thread should be
295
// blocked until a message arrives. The "msg" argument is a result parameter
296
// that is set by the function (i.e., by doing "*msg = ptr"). The "msg"
297
// parameter maybe NULL to indicate that the message should be dropped.
298
//
299
// The return values are the same as for the sys_arch_sem_wait() function:
300
// Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a
301
// timeout.
302
//
303
// Note that a function with a similar name, sys_mbox_fetch(), is implemented
304
// by lwIP.
305
//
306
u32_t
307
sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout)
308
{
309
    void *m;
310
 
311
    if (timeout) {
312
        cyg_tick_count_t start_time = cyg_current_time();
313
 
314
        // Wait for mailbox with timeout
315
        if (!(m = cyg_mbox_timed_get(mbox, start_time + MS_TO_TICKS(timeout))))
316
            return SYS_ARCH_TIMEOUT;
317
        // Map NULL messages
318
        if (m == &null_msg)
319
            m = NULL;
320
        *msg = m;
321
        // Return elapsed time
322
        return TICKS_TO_MS(cyg_current_time() - start_time);
323
    } else {
324
        // Wait for semaphore indefinitely
325
        m = cyg_mbox_get(mbox);
326
        // Map NULL messages
327
        if (m == &null_msg)
328
            m = NULL;
329
        *msg = m;
330
        return 0;
331
    }
332
}
333
 
334
//
335
// This is similar to sys_arch_mbox_fetch, however if a message is not present
336
// in the mailbox, it immediately returns with the code SYS_MBOX_EMPTY. On
337
// success 0 is returned.
338
//
339
// To allow for efficient implementations, this can be defined as a
340
// function-like macro in sys_arch.h instead of a normal function. For example,
341
// a naive implementation could be:
342
//
343
// #define sys_arch_mbox_tryfetch(mbox,msg) sys_arch_mbox_fetch(mbox,msg,1)
344
//
345
// although this would introduce unnecessary delays.
346
//
347
u32_t
348
sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg)
349
{
350
    void *m;
351
 
352
    m = cyg_mbox_tryget(mbox);
353
    if (!m)
354
        return SYS_MBOX_EMPTY;
355
 
356
    if (m == &null_msg)
357
        m = NULL;
358
    *msg = m;
359
 
360
    return 0;
361
}
362
 
363
//
364
// Returns a pointer to the per-thread sys_timeouts structure. In lwIP, each
365
// thread has a list of timeouts which is repressented as a linked list of
366
// sys_timeout structures. The sys_timeouts structure holds a pointer to a
367
// linked list of timeouts. This function is called by the lwIP timeout
368
// scheduler and must not return a NULL value.
369
//
370
// In a single thread sys_arch implementation, this function will simply return
371
// a pointer to a global sys_timeouts variable stored in the sys_arch module.
372
//
373
struct sys_timeouts *
374
sys_arch_timeouts(void)
375
{
376
    cyg_handle_t handle;
377
    struct lwip_thread *t;
378
 
379
    handle = cyg_thread_self();
380
    for (t = threads; t; t = t->next)
381
        if (t->handle == handle)
382
            return &(t->to);
383
 
384
    return &to;
385
}
386
 
387
//
388
// Starts a new thread named "name" with priority "prio" that will begin its
389
// execution in the function "thread()". The "arg" argument will be passed as
390
// an argument to the thread() function. The stack size to used for this thread
391
// is the "stacksize" parameter. The id of the new thread is returned. Both the
392
// id and the priority are system dependent.
393
//
394
sys_thread_t
395
sys_thread_new(char *name, void (* thread)(void *arg), void *arg,
396
               int stacksize, int prio)
397
{
398
    void *stack;
399
 
400
    cyg_mutex_lock(&stack_mutex);
401
    stack = stack_pos;
402
    stack_pos += stacksize;
403
    cyg_mutex_unlock(&stack_mutex);
404
 
405
    if (stack_pos > stack_data + TOTAL_STACKSIZE)
406
        CYG_FAIL("Not enough memory to allocate the thread's stack. You may "
407
                 "want to use cyg_lwip_thread_new() instead of "
408
                 "sys_thread_new() so you can provide external stack memory.");
409
 
410
    return cyg_lwip_thread_new(name, thread, arg, stack, stacksize, prio);
411
}
412
 
413
//
414
// Basically implements the sys_thread_new() call, but adds a "stack" parameter,
415
// allowing clients to provide their own stack buffers.
416
//
417
sys_thread_t
418
cyg_lwip_thread_new(char *name, void (* thread)(void *arg), void *arg,
419
                    void *stack, int stacksize, int prio)
420
{
421
    struct lwip_thread *t;
422
 
423
    t = (struct lwip_thread *) cyg_mempool_var_alloc(
424
            var_handle, sizeof(struct lwip_thread));
425
 
426
    t->next = threads;
427
    t->to.next = NULL;
428
 
429
    threads = t;
430
 
431
    cyg_thread_create(
432
        prio,
433
        (cyg_thread_entry_t *) thread,
434
        (cyg_addrword_t) arg,
435
        name,
436
        stack,
437
        stacksize,
438
        &t->handle,
439
        &t->thread
440
    );
441
    cyg_thread_resume(t->handle);
442
 
443
    return t->handle;
444
}
445
 
446
#endif // !NO_SYS
447
 
448
//
449
// Returns the current time in milliseconds.
450
//
451
u32_t
452
sys_now(void)
453
{
454
    return cyg_current_time() * MS_PER_TICK;
455
}
456
 
457
//
458
// This optional function does a "fast" critical region protection and returns
459
// the previous protection level. This function is only called during very short
460
// critical regions. An embedded system which supports ISR-based drivers might
461
// want to implement this function by disabling interrupts. Task-based systems
462
// might want to implement this by using a mutex or disabling tasking. This
463
// function should support recursive calls from the same task or interrupt. In
464
// other words, sys_arch_protect() could be called while already protected. In
465
// that case the return value indicates that it is already protected.
466
//
467
// sys_arch_protect() is only required if your port is supporting an operating
468
// system.
469
//
470
sys_prot_t
471
sys_arch_protect(void)
472
{
473
    cyg_scheduler_lock();
474
 
475
    return 0;
476
}
477
 
478
//
479
// This optional function does a "fast" set of critical region protection to the
480
// value specified by pval. See the documentation for sys_arch_protect() for
481
// more information. This function is only required if your port is supporting
482
// an operating system.
483
//
484
void
485
sys_arch_unprotect(sys_prot_t pval)
486
{
487
    LWIP_UNUSED_ARG(pval);
488
 
489
    cyg_scheduler_unlock();
490
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.