From 253ec92ca0faf68f5dda9e05662bf1636e223e59 Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Mon, 1 Aug 2011 21:52:57 +0200 Subject: [PATCH 1/6] remove obsolete wait function => IRQ handler uses directly the LwIP stacks --- drivers/net/rtl8139.c | 48 ++----------------------------------------- drivers/net/rtl8139.h | 12 ++--------- 2 files changed, 4 insertions(+), 56 deletions(-) diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index 0ff112ea..1afc6a10 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -110,8 +110,7 @@ static err_t rtl8139if_output(struct netif* netif, struct pbuf* p) return ERR_OK; } -#if 0 -void rtl8139if_input(struct netif* netif, struct pbuf* p) +static void rtl8139if_input(struct netif* netif, struct pbuf* p) { struct eth_hdr *ethhdr; @@ -138,7 +137,6 @@ void rtl8139if_input(struct netif* netif, struct pbuf* p) break; } } -#endif static void rtl_rx_inthandler(struct netif* netif) { @@ -175,8 +173,7 @@ static void rtl_rx_inthandler(struct netif* netif) #if ETH_PAD_SIZE pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ #endif - mailbox_ptr_post(&rtl8139if->mbox, (void*)p); - //rtl8139if_input(netif, p); + rtl8139if_input(netif, p); LINK_STATS_INC(link.recv); } else { LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_rx_inthandler: not enough memory!\n")); @@ -268,46 +265,6 @@ static void rtl8139if_handler(struct state* s) } } -err_t rtl8139if_wait(struct netif* netif, uint32_t poll) -{ - rtl1839if_t* rtl8139if = netif->state; - struct eth_hdr *ethhdr; - struct pbuf *p = NULL; - err_t err = ERR_OK; - - if (poll) { - if (mailbox_ptr_tryfetch(&(rtl8139if->mbox), (void**) &p)) - return err; - } else { - mailbox_ptr_fetch(&(rtl8139if->mbox), (void**) &p); - } - - /* points to packet payload, which starts with an Ethernet header */ - ethhdr = p->payload; - - switch (htons(ethhdr->type)) { - /* IP or ARP packet? */ - case ETHTYPE_ARP: - case ETHTYPE_IP: -#if PPPOE_SUPPORT - /* PPPoE packet? */ - case ETHTYPE_PPPOEDISC: - case ETHTYPE_PPPOE: -#endif /* PPPOE_SUPPORT */ - /* full packet send to tcpip_thread to process */ - if ((err = mynetif->input(p, mynetif)) != ERR_OK) { - LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_poll: IP input error\n")); - pbuf_free(p); - } - break; - default: - pbuf_free(p); - break; - } - - return err; -} - err_t rtl8139if_init(struct netif* netif) { rtl1839if_t* rtl8139if; @@ -348,7 +305,6 @@ err_t rtl8139if_init(struct netif* netif) rtl8139if->tx_buffer[2] = rtl8139if->tx_buffer[1] + 4096; rtl8139if->tx_buffer[3] = rtl8139if->tx_buffer[2] + 4096; - mailbox_ptr_init(&rtl8139if->mbox); netif->state = rtl8139if; mynetif = netif; diff --git a/drivers/net/rtl8139.h b/drivers/net/rtl8139.h index 43bd6fe4..962f5232 100644 --- a/drivers/net/rtl8139.h +++ b/drivers/net/rtl8139.h @@ -23,7 +23,8 @@ #define __HAVE_RTL8139_H__ #include -#include +#include + #if defined(CONFIG_LWIP) && defined(CONFIG_PCI) // the registers are at the following places @@ -226,17 +227,8 @@ typedef struct rtl1839if { uint32_t tx_complete; uint16_t rx_pos; uint8_t tx_inuse[4]; - mailbox_ptr_t mbox; } rtl1839if_t; -/* - * Wait for incoming messages. - * - * poll = 0 : wait blocks until a message is received - * poll != 0: non-blocking wait - */ -err_t rtl8139if_wait(struct netif* netif, uint32_t poll); - /* * Initialize the network driver for the RealTek RTL8139 family */ From 3f2d9a2405f6e390b67905c880e723fd355e8b32 Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Mon, 1 Aug 2011 21:56:16 +0200 Subject: [PATCH 2/6] add support of LwIP's "lightweight" synchronization mechanisms --- lwip/src/arch/sys_arch.c | 22 +++++++++++++++++++++- lwip/src/include/arch/sys_arch.h | 21 +++++++++++++++++++++ lwip/src/include/lwipopts.h | 7 +++++++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/lwip/src/arch/sys_arch.c b/lwip/src/arch/sys_arch.c index 2eef4727..47c6e6ec 100644 --- a/lwip/src/arch/sys_arch.c +++ b/lwip/src/arch/sys_arch.c @@ -74,13 +74,16 @@ sys_msleep(u32_t ms) } } -/* sys_thread_new(): Spawns a new thread with given attributes as supportet +/* sys_thread_new(): Spawns a new thread with given attributes as supported * Note: In MetalSVM this is realized as kernel tasks */ sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio) { tid_t tmp; + + kprintf("Create LWIP task %s\n", name); create_kernel_task(&tmp,thread,arg); + return tmp; } @@ -252,4 +255,21 @@ err_t sys_mutex_new(sys_mutex_t * mutex) return 0; } +#if SYS_LIGHTWEIGHT_PROT +#if MAX_CORES > 1 +static spinlock_irqsave_t lwprot_lock = SPINLOCK_IRQSAVE_INIT; + +sys_prot_t sys_arch_protect(void) +{ + spinlock_irqsave_lock(&lwprot_lock); + return 0; +} + +void sys_arch_unprotect(sys_prot_t pval) +{ + spinlock_irqsave_unlock(&lwprot_lock); +} +#endif +#endif + #endif /* !NO_SYS */ diff --git a/lwip/src/include/arch/sys_arch.h b/lwip/src/include/arch/sys_arch.h index fde4fbc2..eab88cb5 100644 --- a/lwip/src/include/arch/sys_arch.h +++ b/lwip/src/include/arch/sys_arch.h @@ -4,6 +4,7 @@ #include #include #include +#include #define EWOULDBLOCK EAGAIN /* Operation would block */ @@ -22,4 +23,24 @@ typedef struct typedef tid_t* sys_thread_t; +#if SYS_LIGHTWEIGHT_PROT +#if MAX_CORES > 1 +typedef uint32_t sys_prot_t; +sys_prot_t sys_arch_protect(void); +void sys_arch_unprotect(sys_prot_t pval); +#else +typedef uint32_t sys_prot_t; + +static inline sys_prot_t sys_arch_protect(void) +{ + return irq_nested_disable(); +} + +static inline void sys_arch_unprotect(sys_prot_t pval) +{ + irq_nested_enable(pval); +} +#endif +#endif + #endif /* __ARCH_SYS_ARCH_H__ */ diff --git a/lwip/src/include/lwipopts.h b/lwip/src/include/lwipopts.h index 46ac691a..4be7eb4c 100644 --- a/lwip/src/include/lwipopts.h +++ b/lwip/src/include/lwipopts.h @@ -3,6 +3,13 @@ #ifndef __LWIPOPTS_H__ #define __LWIPOPTS_H_ +/** + * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain + * critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#define SYS_LIGHTWEIGHT_PROT 1 + /** * NO_SYS==1: Provides VERY minimal functionality. Otherwise, * use lwIP facilities. From 5c9ef35170fdfb9aa7e66729e6e28f9605827439 Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Mon, 1 Aug 2011 21:57:38 +0200 Subject: [PATCH 3/6] use tcpip_input instead of ethernet_input => With NO_SYS=0, netif->input must be set to tcpip_input for all netif types (whether ethernet, PPP, slipif, etc.) --- kernel/init.c | 102 +++++++++++++++++++++++++------------------------- 1 file changed, 52 insertions(+), 50 deletions(-) diff --git a/kernel/init.c b/kernel/init.c index d9824ef8..28301787 100644 --- a/kernel/init.c +++ b/kernel/init.c @@ -48,8 +48,6 @@ void echo_init(void); void ping_init(void); -static volatile int done = 0; - /* * Note that linker symbols are not variables, they have no memory allocated for * maintaining a value, rather their address is their value. @@ -70,17 +68,42 @@ int lowlevel_init(void) } #if defined(CONFIG_LWIP) && (defined(CONFIG_PCI) || defined(CONFIG_ROCKCREEK)) -static tid_t netid; +static struct netif* default_netif = NULL; +static volatile uint32_t lwip_initialized = 0; -int STDCALL network_task(void* arg) +static void tcp_init_ok(void* e) { - struct netif netif; + kputs("TCP/IP init COMPLETE!!\n"); + lwip_initialized = 1; +} +#endif + +int network_init(void) +{ +#if defined(CONFIG_LWIP) && (defined(CONFIG_PCI) || defined(CONFIG_ROCKCREEK)) struct ip_addr ipaddr; struct ip_addr netmask; struct ip_addr gw; - kputs("Network task is started\n"); + kputs("Initialize network...\n"); + // Initialize lwIP modules + tcpip_init(tcp_init_ok, NULL); + + while(!lwip_initialized) { + reschedule(); + } + + // Set up the lwIP network interface + // Allocate and configure netif + default_netif = (struct netif *) mem_malloc(sizeof(struct netif)); + if(default_netif == NULL) + { + kprintf("ERROR: Out of memory for default netif\n"); + return -ENOMEM; + } + + memset(default_netif, 0x00, sizeof(struct netif)); #ifdef CONFIG_ROCKCREEK /* Set network address variables */ IP4_ADDR(&gw, 192,168,4,254); @@ -88,7 +111,7 @@ int STDCALL network_task(void* arg) IP4_ADDR(&netmask, 255,255,255,0); /* Bring up the network interface */ - if (!netif_add(&netif, &ipaddr, &netmask, &gw, NULL, rckemacif_init, ethernet_input)) { + if (!netif_add(default_netif, &ipaddr, &netmask, &gw, NULL, rckemacif_init, tcpip_input)) { #else /* Clear network address because we use DHCP to get an ip address */ IP4_ADDR(&gw, 0,0,0,0); @@ -96,82 +119,61 @@ int STDCALL network_task(void* arg) IP4_ADDR(&netmask, 0,0,0,0); /* Bring up the network interface */ - if (!netif_add(&netif, &ipaddr, &netmask, &gw, NULL, rtl8139if_init, ethernet_input)) { + if (!netif_add(default_netif, &ipaddr, &netmask, &gw, NULL, rtl8139if_init, tcpip_input)) { #endif kputs("Unable to add network interface\n"); return -ENODEV; } - netif_set_default(&netif); - netif_set_up(&netif); + netif_set_default(default_netif); + netif_set_up(default_netif); /* test if interface is really up */ - if (!netif_is_up(&netif)) { + if (!netif_is_up(default_netif)) { kputs("network interface is not up\n"); return -ENODEV; } #ifndef CONFIG_ROCKCREEK kprintf("Starting DHCPCD...\n"); - dhcp_start(&netif); + dhcp_start(default_netif); + int mscnt = 0; /* wait for ip address */ - while(!netif.ip_addr.addr) { - rtl8139if_wait(&netif, 1); - reschedule(); + while(!default_netif->ip_addr.addr) { + sys_msleep(DHCP_FINE_TIMER_MSECS); + dhcp_fine_tmr(); + mscnt += DHCP_FINE_TIMER_MSECS; + if (mscnt >= DHCP_COARSE_TIMER_SECS*1000) { + dhcp_coarse_tmr(); + mscnt = 0; + } } #else - mmnif_open(); + //mmnif_open(); #endif // start echo and ping server echo_init(); ping_init(); - - while(!done) { -#ifdef CONFIG_PCI - rtl8139if_wait(&netif, 0); -#elif defined(CONFIG_ROCKCREEK) - rckemacif_wait(&netif, 0); -#endif - } - -#ifndef CONFIG_ROCKCREEK - dhcp_release(&netif); - dhcp_stop(&netif); #endif return 0; } -#endif int network_shutdown(void) { #if defined(CONFIG_LWIP) && defined(CONFIG_ROCKCREEK) - mmnif_close(); + //mmnif_close(); +#elif defined(CONFIG_LWIP) && defined(CONFIG_PCI) + dhcp_release(default_netif); + dhcp_stop(default_netif); #endif - done = 1; + + mem_free(default_netif); + default_netif = NULL; return 0; } -static void tcp_init_ok(void* e) -{ - kprintf("TCP/IP init COMPLETE!!"); -} -int network_init(void) -{ - int ret = 0; - -#if defined(CONFIG_LWIP) - // Initialize lwIP modules - tcpip_init(tcp_init_ok, NULL); -#endif - -#if defined(CONFIG_LWIP) && (defined(CONFIG_PCI) || defined(CONFIG_ROCKCREEK)) - ret = create_kernel_task(&netid, network_task, NULL); -#endif - - return ret; -} From 2538fd7d0b9aaa6035ce77d6664774e64e8c0427 Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Mon, 1 Aug 2011 22:00:05 +0200 Subject: [PATCH 4/6] use nicer output messages --- kernel/ping.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/ping.c b/kernel/ping.c index 77facfd7..7d81500f 100644 --- a/kernel/ping.c +++ b/kernel/ping.c @@ -212,11 +212,11 @@ ping_thread(void *arg) lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); - for(i=0; i<10; i++) { + for(i=0; i<5; i++) { ping_target = PING_TARGET; if (ping_send(s, &ping_target) == ERR_OK) { - LWIP_DEBUGF( PING_DEBUG, ("ping: send ")); + LWIP_DEBUGF( PING_DEBUG, ("ping: send on core %d to " , CORE_ID)); ip_addr_debug_print(PING_DEBUG, &ping_target); LWIP_DEBUGF( PING_DEBUG, ("\n")); From d5bfc4f28cef1aec13d3d0bf8f6de16281d3b4f7 Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Mon, 1 Aug 2011 22:01:39 +0200 Subject: [PATCH 5/6] avoid races on SMP systems => signalizes with a new flag, that a task switch is finished --- arch/x86/include/asm/tasks.h | 2 +- arch/x86/kernel/entry.asm | 4 +- arch/x86/kernel/gdt.c | 19 +----- arch/x86/kernel/isrs.c | 4 +- include/metalsvm/stddef.h | 11 ++++ include/metalsvm/tasks_types.h | 14 ++-- kernel/tasks.c | 117 +++++++++++++++++++++++++++++---- kernel/tests.c | 14 ++-- 8 files changed, 136 insertions(+), 49 deletions(-) diff --git a/arch/x86/include/asm/tasks.h b/arch/x86/include/asm/tasks.h index 0ee4f9dd..c12f946a 100644 --- a/arch/x86/include/asm/tasks.h +++ b/arch/x86/include/asm/tasks.h @@ -59,7 +59,7 @@ void switch_task(uint32_t id); * - 0 on success * - -EINVAL (-22) on failure */ -int create_default_frame(task_t* task, entry_point_t ep, void* arg); +int create_default_frame(task_t* task, internal_entry_point_t ep, void* arg); /** @brief Register a task's TSS at GDT * diff --git a/arch/x86/kernel/entry.asm b/arch/x86/kernel/entry.asm index 852af114..e2e2d84a 100644 --- a/arch/x86/kernel/entry.asm +++ b/arch/x86/kernel/entry.asm @@ -496,8 +496,8 @@ global apic_lint1 global apic_error global apic_svr -global tss_switch -tss_switch: +global switch_task +switch_task: mov eax, [esp+4] add ax, WORD 5 mov bx, WORD 8 diff --git a/arch/x86/kernel/gdt.c b/arch/x86/kernel/gdt.c index f15057f7..9441410a 100644 --- a/arch/x86/kernel/gdt.c +++ b/arch/x86/kernel/gdt.c @@ -52,23 +52,6 @@ size_t get_stack(uint32_t id) return (size_t) kstacks[id] + KERNEL_STACK_SIZE - sizeof(size_t); } -void switch_task(uint32_t id) -{ -#if MAX_CORES > 1 - /* - * On SMP systems, the task switch on an other could be in progress... - * => we need to check, if the task is still busy - */ - volatile gdt_entry_t* newgdt = (volatile gdt_entry_t*) gdt+id-5; - - while (newgdt->access & GDT_FLAG_TSS_BUSY) { - NOP1; - } -#endif - - tss_switch(id); -} - int register_task(task_t* task) { uint16_t sel; uint32_t id = task->id; @@ -142,7 +125,7 @@ int arch_fork(task_t* task) return 0; } -int create_default_frame(task_t* task, entry_point_t ep, void* arg) +int create_default_frame(task_t* task, internal_entry_point_t ep, void* arg) { uint16_t cs = 0x08; uint16_t ds = 0x10; diff --git a/arch/x86/kernel/isrs.c b/arch/x86/kernel/isrs.c index c37f2689..f1e2d9cc 100644 --- a/arch/x86/kernel/isrs.c +++ b/arch/x86/kernel/isrs.c @@ -229,8 +229,8 @@ static void fault_handler(struct state *s) { if (s->int_no < 32) { kputs(exception_messages[s->int_no]); - kprintf(" Exception (%d) at 0x%x:0x%x on core %d, error code 0x%x, eflags 0x%x\n", - s->int_no, s->cs, CORE_ID, s->eip, s->error, s->eflags); + kprintf(" Exception (%d) at 0x%x:0x%x on core %u, error code 0x%x, eflags 0x%x\n", + s->int_no, s->cs, s->eip, CORE_ID, s->error, s->eflags); /* Now, we signalize that we have handled the interrupt */ if (apic_is_enabled()) diff --git a/include/metalsvm/stddef.h b/include/metalsvm/stddef.h index a34ccf10..725365e2 100644 --- a/include/metalsvm/stddef.h +++ b/include/metalsvm/stddef.h @@ -36,6 +36,7 @@ typedef unsigned int tid_t; #define per_core(name) name #define DECLARE_PER_CORE(type, name) extern type name; #define DEFINE_PER_CORE(type, name, def_value) type name = def_value; +#define DEFINE_PER_CORE_STATIC(type, name, def_value) static type name = def_value; #define CORE_ID 0 #else #define per_core(name) (*__get_percore_##name()) @@ -51,6 +52,16 @@ typedef unsigned int tid_t; } #define DEFINE_PER_CORE(type, name, def_value) \ aligned_##name name[MAX_CORES] = {[0 ... MAX_CORES-1] = {def_value}}; +#define DEFINE_PER_CORE_STATIC(type, name, def_value) \ + typedef struct { type var __attribute__ ((aligned (CACHE_LINE))); } aligned_##name;\ + static aligned_##name name[MAX_CORES] = {[0 ... MAX_CORES-1] = {def_value}}; \ + inline static type* __get_percore_##name(void) {\ + type* ret; \ + uint32_t flags = irq_nested_disable(); \ + ret = &(name[smp_id()].var); \ + irq_nested_enable(flags);\ + return ret; \ + } #define CORE_ID smp_id() #endif diff --git a/include/metalsvm/tasks_types.h b/include/metalsvm/tasks_types.h index b22ca7ce..c6e835e5 100644 --- a/include/metalsvm/tasks_types.h +++ b/include/metalsvm/tasks_types.h @@ -41,17 +41,19 @@ extern "C" { #endif #define TASK_INVALID 0 -#define TASK_READY 1 +#define TASK_READY 1 #define TASK_RUNNING 2 #define TASK_BLOCKED 3 #define TASK_FINISHED 4 -#define TASK_IDLE 5 +#define TASK_IDLE 5 -#define TASK_DEFAULT_FLAGS 0 -#define TASK_FPU_INIT (1 << 0) -#define TASK_FPU_USED (1 << 1) +#define TASK_DEFAULT_FLAGS 0 +#define TASK_FPU_INIT (1 << 0) +#define TASK_FPU_USED (1 << 1) +#define TASK_SWITCH_IN_PROGESS (1 << 2) -typedef int (STDCALL *entry_point_t)(void*); +typedef int (*entry_point_t)(void*); +typedef int (STDCALL *internal_entry_point_t)(void*); struct page_dir; /* @brief The task_t structure */ diff --git a/kernel/tasks.c b/kernel/tasks.c index 37856b18..48182a9b 100644 --- a/kernel/tasks.c +++ b/kernel/tasks.c @@ -52,6 +52,7 @@ static task_t task_table[MAX_TASKS] = { \ static spinlock_irqsave_t table_lock = SPINLOCK_IRQSAVE_INIT; DEFINE_PER_CORE(task_t*, current_task, task_table+0); +DEFINE_PER_CORE_STATIC(task_t*, old_task, NULL); /** @brief helper function for the assembly code to determine the current task * @return Pointer to the task_t structure of current task @@ -170,6 +171,24 @@ void NORETURN abort(void) { do_exit(-1); } +/* + * @brief: if the task switch is finished, we reset + * the TASK_SWITCH_IN_PROGRESS bit + */ +inline static void task_switch_finished(void) +{ + uint32_t flags = irq_nested_disable(); + + // do we already reset the TASK_SWITCH_IN_PROGRESS bit? + task_t* old = per_core(old_task); + if (old) { + old->flags &= ~TASK_SWITCH_IN_PROGESS; + per_core(old_task) = NULL; + } + + irq_nested_enable(flags); +} + /** @brief Create a task with a specific entry point * * @param id Pointer to a tid_t struct were the id shall be set @@ -179,7 +198,7 @@ void NORETURN abort(void) { * - 0 on success * - -ENOMEM (-12) or -EINVAL (-22) on failure */ -static int create_task(tid_t* id, entry_point_t ep, void* arg) +static int create_task(tid_t* id, internal_entry_point_t ep, void* arg) { task_t* curr_task; int ret = -ENOMEM; @@ -229,7 +248,6 @@ create_task_out: return ret; } - int sys_fork(void) { int ret = -ENOMEM; @@ -292,6 +310,10 @@ int sys_fork(void) // Leave the function without releasing the locks // because the locks are already released // by the parent task! + + // first switch to the new current task + // => signalizes a successful task switch + task_switch_finished(); return 0; } @@ -310,15 +332,54 @@ create_task_out: return ret; } -int create_kernel_task(tid_t* id, entry_point_t ep, void* arg) +/** @brief Structure which keeps all + * relevant data for a new kernel task to start */ +typedef struct { + /// entry point of the kernel task + entry_point_t func; + /// arguments + void* args; +} kernel_args_t; + +/** @brief This call is used to adapt create_task calls + * which want to have a start function and argument list */ +static int STDCALL kernel_entry(void* args) { - return create_task(id, ep, arg); + int ret; + kernel_args_t* kernel_args = (kernel_args_t*) args; + + // first switch to the new current task + // => signalizes a successful task switch + task_switch_finished(); + + if (BUILTIN_EXPECT(!kernel_args, 0)) + return -EINVAL; + + ret = kernel_args->func(kernel_args->args); + + kfree(kernel_args, sizeof(kernel_args_t)); + + return ret; +} + +int create_kernel_task(tid_t* id, entry_point_t ep, void* args) +{ + kernel_args_t* kernel_args; + + kernel_args = kmalloc(sizeof(kernel_args_t)); + if (BUILTIN_EXPECT(!kernel_args, 0)) + return -ENOMEM; + + kernel_args->func = ep; + kernel_args->args = args; + + return create_task(id, kernel_entry, kernel_args); } #define MAX_ARGS (PAGE_SIZE - 2*sizeof(int) - sizeof(vfs_node_t*)) /** @brief Structure which keeps all - * relevant data for a new task to start */ + * relevant data for a new user task to start */ typedef struct { /// Points to the node with the executable in the file system vfs_node_t* node; @@ -528,7 +589,20 @@ invalid: * which want to have a start function and argument list */ static int STDCALL user_entry(void* arg) { - return load_task((load_args_t*) arg); + int ret; + + // first switch to the new current task + // => signalizes a successful task switch + task_switch_finished(); + + if (BUILTIN_EXPECT(!arg, 0)) + return -EINVAL; + + ret = load_task((load_args_t*) arg); + + kfree(arg, sizeof(load_args_t)); + + return ret; } /** @brief Luxus-edition of create_user_task functions. Just call with an exe name @@ -717,14 +791,14 @@ int block_task(tid_t id) spinlock_irqsave_lock(&table_lock); - if ((task_table[id].status == TASK_RUNNING) || (task_table[id].status == TASK_READY)) { + if ((task_table[id].status == TASK_RUNNING) || (task_table[id].status == TASK_READY)) { task_table[id].status = TASK_BLOCKED; ret = 0; } else kprintf("Unable to block task %d!\n", id); - spinlock_irqsave_unlock(&table_lock); + spinlock_irqsave_unlock(&table_lock); - return ret; + return ret; } /** @brief _The_ scheduler procedure @@ -738,13 +812,18 @@ void scheduler(void) unsigned int i; unsigned int new_id; + // let's play it save + // => check if we already signalizes that the previous switch + // is finished + task_switch_finished(); + #if MAX_CORES > 1 spinlock_irqsave_lock(&table_lock); #endif orig_task = curr_task = per_core(current_task); - /* signalize that this task could be reused */ + /* signalizes that this task could be reused */ if (curr_task->status == TASK_FINISHED) curr_task->status = TASK_INVALID; @@ -757,16 +836,26 @@ void scheduler(void) for(i=1, new_id=(curr_task->id + 1) % MAX_TASKS; istatus == TASK_RUNNING) + if ((task_table[new_id].status == TASK_READY) && !(task_table[new_id].flags & TASK_SWITCH_IN_PROGESS)) { + if (curr_task->status == TASK_RUNNING) { curr_task->status = TASK_READY; + curr_task->flags |= TASK_SWITCH_IN_PROGESS; + per_core(old_task) = curr_task; + } else per_core(old_task) = NULL; + task_table[new_id].status = TASK_RUNNING; curr_task = per_core(current_task) = task_table+new_id; goto get_task_out; } + + //if ((task_table[new_id].status == TASK_READY) && (task_table[new_id].flags & TASK_SWITCH_IN_PROGESS)) + // kprintf("task switch %d is in progress\n", new_id); } + // old task will never rescheduled + per_core(old_task) = NULL; + if ((curr_task->status == TASK_RUNNING) || (curr_task->status == TASK_IDLE)) goto get_task_out; @@ -783,8 +872,10 @@ get_task_out: spinlock_irqsave_unlock(&table_lock); #endif - if (curr_task != orig_task) + if (curr_task != orig_task) { switch_task(new_id); + task_switch_finished(); + } } void reschedule(void) diff --git a/kernel/tests.c b/kernel/tests.c index d3f8a68a..a39f55a0 100644 --- a/kernel/tests.c +++ b/kernel/tests.c @@ -39,7 +39,7 @@ static sem_t consuming, producing; static mailbox_int32_t mbox; static int val = 0; -static int STDCALL consumer(void* arg) +static int consumer(void* arg) { int i, m = 0; @@ -58,7 +58,7 @@ static int STDCALL consumer(void* arg) return 0; } -static int STDCALL producer(void* arg) +static int producer(void* arg) { int i; int mail[5] = {1, 2, 3, 4, 5}; @@ -78,7 +78,7 @@ static int STDCALL producer(void* arg) return 0; } -static int STDCALL foo(void* arg) +static int foo(void* arg) { int i; @@ -94,7 +94,7 @@ static int STDCALL foo(void* arg) } #ifdef CONFIG_ROCKCREEK -int STDCALL mail_ping(void* arg) { +int mail_ping(void* arg) { int i; for(i=0; i<20; i++) { @@ -107,7 +107,7 @@ int STDCALL mail_ping(void* arg) { } #endif -static int STDCALL join_test(void* arg) +static int join_test(void* arg) { tid_t id, ret; int result = -1234; @@ -125,7 +125,7 @@ static int STDCALL join_test(void* arg) } #if defined(CONFIG_LWIP) && defined(CONFIG_ROCKCREEK) -static int STDCALL server_task(void* e) +static int server_task(void* e) { int sockfd, newsockfd, portno, clilen; char buffer[256]; @@ -193,7 +193,7 @@ static int STDCALL server_task(void* e) return 0; } -static int STDCALL client_task(void* e) +static int client_task(void* e) { char dir[256]; int sd; From 5ffa35351cf740315c453ffb2bb47662496a98ee Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Mon, 1 Aug 2011 13:26:11 -0700 Subject: [PATCH 6/6] minor optimizations... IRQ handler calls directly the LwIP stack --- drivers/net/rckemac.c | 74 +++++++++++++++++-------------------------- drivers/net/rckemac.h | 10 ------ 2 files changed, 29 insertions(+), 55 deletions(-) diff --git a/drivers/net/rckemac.c b/drivers/net/rckemac.c index b2b07f4e..cd3409e9 100644 --- a/drivers/net/rckemac.c +++ b/drivers/net/rckemac.c @@ -258,6 +258,34 @@ again: return ERR_OK; } +static void rckemacif_input(struct netif* netif, struct pbuf* p) +{ + struct eth_hdr *ethhdr; + + /* points to packet payload, which starts with an Ethernet header */ + ethhdr = p->payload; + + switch (htons(ethhdr->type)) { + /* IP or ARP packet? */ + case ETHTYPE_ARP: + case ETHTYPE_IP: +#if PPPOE_SUPPORT + /* PPPoE packet? */ + case ETHTYPE_PPPOEDISC: + case ETHTYPE_PPPOE: +#endif /* PPPOE_SUPPORT */ + /* full packet send to tcpip_thread to process */ + if (mynetif->input(p, mynetif) != ERR_OK) { + LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_input: IP input error\n")); + pbuf_free(p); + } + break; + default: + pbuf_free(p); + break; + } +} + static void rckemacif_rx_handler(struct netif* netif, unsigned int write_offset) { rckemacif_t* rckemacif = netif->state; @@ -372,7 +400,7 @@ out: #if ETH_PAD_SIZE pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ #endif - mailbox_ptr_post(&rckemacif->mbox, (void*)p); + rckemacif_input(netif, p); LINK_STATS_INC(link.recv); } else { LWIP_DEBUGF(NETIF_DEBUG, ("rckemacif_rx_inthandler: not enough memory!\n")); @@ -422,48 +450,6 @@ nexttry: *((volatile unsigned*) (FPGA_BASE + IRQ_RESET + rckemacif->core * 2 * 4)) = (1 << rckemacif->num_emac); } -err_t rckemacif_wait(struct netif* netif, uint32_t poll) -{ - rckemacif_t* rckemacif = netif->state; - struct eth_hdr *ethhdr; - struct pbuf *p = NULL; - err_t err = ERR_OK; - - if (poll) { - if (mailbox_ptr_tryfetch(&(rckemacif->mbox), (void**) &p)) - return err; - } else { - mailbox_ptr_fetch(&(rckemacif->mbox), (void**) &p); - } - - /* points to packet payload, which starts with an Ethernet header */ - ethhdr = p->payload; - - //LWIP_DEBUGF(NETIF_DEBUG, ("Got packet of type 0x%x!\n", htons(ethhdr->type))); - - switch (htons(ethhdr->type)) { - /* IP or ARP packet? */ - case ETHTYPE_ARP: - case ETHTYPE_IP: -#if PPPOE_SUPPORT - /* PPPoE packet? */ - case ETHTYPE_PPPOEDISC: - case ETHTYPE_PPPOE: -#endif /* PPPOE_SUPPORT */ - /* full packet send to tcpip_thread to process */ - if ((err = mynetif->input(p, mynetif)) != ERR_OK) { - LWIP_DEBUGF(NETIF_DEBUG, ("rckemacif_poll: IP input error\n")); - pbuf_free(p); - } - break; - default: - pbuf_free(p); - break; - } - - return err; -} - err_t rckemacif_init(struct netif* netif) { rckemacif_t* rckemacif; @@ -516,8 +502,6 @@ err_t rckemacif_init(struct netif* netif) memset(rckemacif->tx_buffer, 0x00, 0x20); memset(rckemacif->tx_buffer + 0x20, 0xDA, BUFFER_SIZE - 0x20); rckemacif->tx_buffer_max = CLINE_PACKETS(BUFFER_SIZE) - 1; - - mailbox_ptr_init(&rckemacif->mbox); netif->state = rckemacif; /* Depending on core location read own private data diff --git a/drivers/net/rckemac.h b/drivers/net/rckemac.h index 2c53523f..2796f14d 100644 --- a/drivers/net/rckemac.h +++ b/drivers/net/rckemac.h @@ -21,7 +21,6 @@ #define __HAVE_RCKEMAC_H__ #include -#include #if defined(CONFIG_LWIP) && defined(CONFIG_ROCKCREEK) @@ -40,17 +39,8 @@ typedef struct rckemacif { void* irq_address; uint32_t core; uint32_t num_emac; - mailbox_ptr_t mbox; } rckemacif_t; -/* - * Wait for incoming messages. - * - * poll = 0 : wait blocks until a message is received - * poll != 0: non-blocking wait - */ -err_t rckemacif_wait(struct netif* netif, uint32_t poll); - /* * Initialize the eMAC network driver */