From 98fbb855fb1f5ff643b65125faf90b8cf5f19057 Mon Sep 17 00:00:00 2001 From: davidhaas Date: Tue, 4 Feb 2003 22:52:22 +0000 Subject: [PATCH] Added lightweight protection. In coldfire this is implemented by disabling interrupts. In unixsim this is implemented by using a mutex. Uses #define SYS_LIGHTWEIGHT_PROT to enable. It is enabled in coldfire by default, but disabled in unixsim. Fixes bug 2005 if you enable SYS_LIGHTWEIGHT_PROT. So the bug is closed. --- src/core/mem.c | 2 +- src/core/memp.c | 21 ++++++ src/core/pbuf.c | 147 +++++++++++++++++++++++++++++++++-------- src/include/lwip/sys.h | 8 +++ 4 files changed, 151 insertions(+), 27 deletions(-) diff --git a/src/core/mem.c b/src/core/mem.c index aaba155f..4fa300ce 100644 --- a/src/core/mem.c +++ b/src/core/mem.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * diff --git a/src/core/memp.c b/src/core/memp.c index 4846f616..777fbb99 100644 --- a/src/core/memp.c +++ b/src/core/memp.c @@ -212,9 +212,19 @@ void * memp_mallocp(memp_t type) { void *mem; +#ifdef SYS_LIGHTWEIGHT_PROT + u32_t old_level = sys_arch_protect(); +#else /* SYS_LIGHTWEIGHT_PROT */ sys_sem_wait(mutex); +#endif /* SYS_LIGHTWEIGHT_PROT */ + mem = memp_malloc(type); + +#ifdef SYS_LIGHTWEIGHT_PROT + sys_arch_unprotect(old_level); +#else /* SYS_LIGHTWEIGHT_PROT */ sys_sem_signal(mutex); +#endif /* SYS_LIGHTWEIGHT_PROT */ return mem; } /*-----------------------------------------------------------------------------------*/ @@ -243,8 +253,19 @@ memp_free(memp_t type, void *mem) void memp_freep(memp_t type, void *mem) { +#ifdef SYS_LIGHTWEIGHT_PROT + u32_t old_level = sys_arch_protect(); +#else /* SYS_LIGHTWEIGHT_PROT */ sys_sem_wait(mutex); +#endif /* SYS_LIGHTWEIGHT_PROT */ + memp_free(type, mem); + +#ifdef SYS_LIGHTWEIGHT_PROT + sys_arch_unprotect(old_level); +#else /* SYS_LIGHTWEIGHT_PROT */ sys_sem_signal(mutex); +#endif /* SYS_LIGHTWEIGHT_PROT */ + } /*-----------------------------------------------------------------------------------*/ diff --git a/src/core/pbuf.c b/src/core/pbuf.c index 6c11097f..ed551a92 100644 --- a/src/core/pbuf.c +++ b/src/core/pbuf.c @@ -52,8 +52,12 @@ #include "arch/perf.h" static u8_t pbuf_pool_memory[(PBUF_POOL_SIZE * MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE + sizeof(struct pbuf)))]; + +#ifndef SYS_LIGHTWEIGHT_PROT static volatile u8_t pbuf_pool_free_lock, pbuf_pool_alloc_lock; static sys_sem_t pbuf_pool_free_sem; +#endif + static struct pbuf *pbuf_pool = NULL; static struct pbuf *pbuf_pool_alloc_cache = NULL; static struct pbuf *pbuf_pool_free_cache = NULL; @@ -99,10 +103,11 @@ pbuf_init(void) are no more pbufs in the pool. */ q->next = NULL; +#ifndef SYS_LIGHTWEIGHT_PROT pbuf_pool_alloc_lock = 0; pbuf_pool_free_lock = 0; pbuf_pool_free_sem = sys_sem_new(1); - +#endif } /*-----------------------------------------------------------------------------------*/ /* The following two functions are only called from pbuf_alloc(). */ @@ -112,6 +117,12 @@ pbuf_pool_alloc(void) { struct pbuf *p = NULL; +#ifdef SYS_LIGHTWEIGHT_PROT + u32_t old_level; + + old_level = sys_arch_protect(); +#endif /* SYS_LIGHTWEIGHT_PROT */ + /* First, see if there are pbufs in the cache. */ if(pbuf_pool_alloc_cache) { p = pbuf_pool_alloc_cache; @@ -119,6 +130,7 @@ pbuf_pool_alloc(void) pbuf_pool_alloc_cache = p->next; } } else { +#ifndef SYS_LIGHTWEIGHT_PROT /* Next, check the actual pbuf pool, but if the pool is locked, we pretend to be out of buffers and return NULL. */ if(pbuf_pool_free_lock) { @@ -129,18 +141,21 @@ pbuf_pool_alloc(void) } pbuf_pool_alloc_lock = 1; if(!pbuf_pool_free_lock) { +#endif /* SYS_LIGHTWEIGHT_PROT */ p = pbuf_pool; if(p) { pbuf_pool = p->next; } +#ifndef SYS_LIGHTWEIGHT_PROT #ifdef PBUF_STATS } else { ++lwip_stats.pbuf.alloc_locked; #endif /* PBUF_STATS */ } pbuf_pool_alloc_lock = 0; +#endif /* SYS_LIGHTWEIGHT_PROT */ } - + #ifdef PBUF_STATS if(p != NULL) { ++lwip_stats.pbuf.used; @@ -150,6 +165,10 @@ pbuf_pool_alloc(void) } #endif /* PBUF_STATS */ +#ifdef SYS_LIGHTWEIGHT_PROT + sys_arch_unprotect(old_level); +#endif /* SYS_LIGHTWEIGHT_PROT */ + return p; } /*-----------------------------------------------------------------------------------*/ @@ -157,19 +176,33 @@ static void pbuf_pool_free(struct pbuf *p) { struct pbuf *q; +#ifdef SYS_LIGHTWEIGHT_PROT + u32_t old_level; +#endif /* SYS_LIGHTWEIGHT_PROT */ + + +#ifdef SYS_LIGHTWEIGHT_PROT + old_level = sys_arch_protect(); +#endif /* SYS_LIGHTWEIGHT_PROT */ #ifdef PBUF_STATS for(q = p; q != NULL; q = q->next) { --lwip_stats.pbuf.used; } #endif /* PBUF_STATS */ - + +#ifdef SYS_LIGHTWEIGHT_PROT + old_level = sys_arch_protect(); +#endif /* SYS_LIGHTWEIGHT_PROT */ if(pbuf_pool_alloc_cache == NULL) { pbuf_pool_alloc_cache = p; } else { for(q = pbuf_pool_alloc_cache; q->next != NULL; q = q->next); q->next = p; } +#ifdef SYS_LIGHTWEIGHT_PROT + sys_arch_unprotect(old_level); +#endif /* SYS_LIGHTWEIGHT_PROT */ } /*-----------------------------------------------------------------------------------*/ /* pbuf_alloc(): @@ -313,12 +346,19 @@ void pbuf_refresh(void) { struct pbuf *p; +#ifdef SYS_LIGHTWEIGHT_PROT + u32_t old_level; + old_level = sys_arch_protect(); +#else /* SYS_LIGHTWEIGHT_PROT */ sys_sem_wait(pbuf_pool_free_sem); +#endif /* else SYS_LIGHTWEIGHT_PROT */ if(pbuf_pool_free_cache != NULL) { +#ifndef SYS_LIGHTWEIGHT_PROT pbuf_pool_free_lock = 1; if(!pbuf_pool_alloc_lock) { +#endif /* SYS_LIGHTWEIGHT_PROT */ if(pbuf_pool == NULL) { pbuf_pool = pbuf_pool_free_cache; } else { @@ -326,23 +366,48 @@ pbuf_refresh(void) p->next = pbuf_pool_free_cache; } pbuf_pool_free_cache = NULL; +#ifndef SYS_LIGHTWEIGHT_PROT #ifdef PBUF_STATS } else { ++lwip_stats.pbuf.refresh_locked; #endif /* PBUF_STATS */ } - pbuf_pool_free_lock = 0; + pbuf_pool_free_lock = 0; +#endif /* SYS_LIGHTWEIGHT_PROT */ } - +#ifdef SYS_LIGHTWEIGHT_PROT + sys_arch_unprotect(old_level); +#else /* SYS_LIGHTWEIGHT_PROT */ sys_sem_signal(pbuf_pool_free_sem); +#endif /* SYS_LIGHTWEIGHT_PROT */ } -#define PBUF_POOL_FREE(p) do { \ - sys_sem_wait(pbuf_pool_free_sem); \ - p->next = pbuf_pool_free_cache; \ - pbuf_pool_free_cache = p; \ - sys_sem_signal(pbuf_pool_free_sem); \ + +#ifdef PBUF_STATS +#define DEC_PBUF_STATS do { --lwip_stats.pbuf.used; } while (0) +#else /* PBUF_STATS */ +#define DEC_PBUF_STATS +#endif /* PBUF_STATS */ + +#define PBUF_POOL_FAST_FREE(p) do { \ + p->next = pbuf_pool_free_cache; \ + pbuf_pool_free_cache = p; \ + DEC_PBUF_STATS; \ + } while (0) + +#ifdef SYS_LIGHTWEIGHT_PROT +#define PBUF_POOL_FREE(p) do { \ + u32_t old_level = sys_arch_protect(); \ + PBUF_POOL_FAST_FREE(p); \ + sys_arch_unprotect(old_level); \ } while(0) +#else /* SYS_LIGHTWEIGHT_PROT */ +#define PBUF_POOL_FREE(p) do { \ + sys_sem_wait(pbuf_pool_free_sem); \ + PBUF_POOL_FAST_FREE(p); \ + sys_sem_signal(pbuf_pool_free_sem); \ + } while(0) +#endif /* SYS_LIGHTWEIGHT_PROT */ /*-----------------------------------------------------------------------------------*/ /* pbuf_realloc: * @@ -389,9 +454,6 @@ pbuf_realloc(struct pbuf *p, u16_t size) while(q != NULL) { r = q->next; PBUF_POOL_FREE(q); -#ifdef PBUF_STATS - --lwip_stats.pbuf.used; -#endif /* PBUF_STATS */ q = r; } break; @@ -477,7 +539,10 @@ pbuf_free(struct pbuf *p) { struct pbuf *q; u8_t count = 0; - +#ifdef SYS_LIGHTWEIGHT_PROT + u32_t old_level; +#endif /* SYS_LIGHTWEIGHT_PROT */ + if(p == NULL) { return 0; } @@ -489,14 +554,23 @@ pbuf_free(struct pbuf *p) p->flags == PBUF_FLAG_RAM); ASSERT("pbuf_free: p->ref > 0", p->ref > 0); - + +#ifdef SYS_LIGHTWEIGHT_PROT + /* Since decrementing ref cannot be guarranteed to be a single machine operation + we must protect it. Also, the later test of ref must be protected. + */ + old_level = sys_arch_protect(); +#endif /* SYS_LIGHTWEIGHT_PROT */ /* Decrement reference count. */ p->ref--; q = NULL; /* If reference count == 0, actually deallocate pbuf. */ if(p->ref == 0) { - +#ifdef SYS_LIGHTWEIGHT_PROT + sys_arch_unprotect(old_level); +#endif + while(p != NULL) { /* Check if this is a pbuf from the pool. */ if(p->flags == PBUF_FLAG_POOL) { @@ -504,21 +578,25 @@ pbuf_free(struct pbuf *p) p->payload = (void *)((u8_t *)p + sizeof(struct pbuf)); q = p->next; PBUF_POOL_FREE(p); -#ifdef PBUF_STATS - --lwip_stats.pbuf.used; -#endif /* PBUF_STATS */ - } else if(p->flags == PBUF_FLAG_ROM) { - q = p->next; - memp_freep(MEMP_PBUF, p); } else { - q = p->next; - mem_free(p); + if(p->flags == PBUF_FLAG_ROM) { + q = p->next; + memp_freep(MEMP_PBUF, p); + } else { + q = p->next; + mem_free(p); + } } + p = q; ++count; } pbuf_refresh(); } +#ifdef SYS_LIGHTWEIGHT_PROT + else + sys_arch_unprotect(old_level); +#endif /* SYS_LIGHTWEIGHT_PROT */ PERF_STOP("pbuf_free"); @@ -553,10 +631,21 @@ pbuf_clen(struct pbuf *p) void pbuf_ref(struct pbuf *p) { +#ifdef SYS_LIGHTWEIGHT_PROT + u32_t old_level; +#endif /* SYS_LIGHTWEIGHT_PROT */ + if(p == NULL) { return; } + +#ifdef SYS_LIGHTWEIGHT_PROT + old_level = sys_arch_protect(); +#endif /* SYS_LIGHTWEIGHT_PROT */ ++(p->ref); +#ifdef SYS_LIGHTWEIGHT_PROT + sys_arch_unprotect(old_level); +#endif /* SYS_LIGHTWEIGHT_PROT */ } /*------------------------------------------------------------------------------*/ @@ -567,10 +656,18 @@ pbuf_ref(struct pbuf *p) void pbuf_ref_chain(struct pbuf *p) { +#ifdef SYS_LIGHTWEIGHT_PROT + u32_t old_level = sys_arch_protect(); +#endif /* SYS_LIGHTWEIGHT_PROT */ + while (p != NULL) { p->ref++; p=p->next; } + +#ifdef SYS_LIGHTWEIGHT_PROT + sys_arch_unprotect(old_level); +#endif /* SYS_LIGHTWEIGHT_PROT */ } /*-----------------------------------------------------------------------------------*/ /* pbuf_chain(): @@ -665,5 +762,3 @@ pbuf_unref(struct pbuf *f) } return f; } - - diff --git a/src/include/lwip/sys.h b/src/include/lwip/sys.h index 18f47290..3523f0e7 100644 --- a/src/include/lwip/sys.h +++ b/src/include/lwip/sys.h @@ -103,6 +103,14 @@ u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout); void sys_mbox_free(sys_mbox_t mbox); void sys_mbox_fetch(sys_mbox_t mbox, void **msg); +/* Critical Region Protection */ +/* These functions must be implemented in the sys_arch.c file. + In some implementations they can provide a more light-weight protection + mechanism than using semaphores. Otherwise semaphores can be used for + implementation */ +u32_t sys_arch_protect(void); +void sys_arch_unprotect(u32_t pval); + /* Thread functions. */ void sys_thread_new(void (* thread)(void *arg), void *arg);