# HG changeset patch # User jlarmour # Date 996841652 0 # Node ID 3902ef905c9c93de70fd8b71d69772286bc7ff6a # Parent e7780801e1a73964a6fbf9481f1cddf4a06ebfaa Merge from eCos master repository on 2001-08-03-06:43:13-BST diff --git a/packages/ChangeLog b/packages/ChangeLog --- a/packages/ChangeLog +++ b/packages/ChangeLog @@ -1,3 +1,8 @@ +2001-07-31 Bart Veer + + * pkgconf/rules.mak: + Fix header file dependencies for testcases. + 2001-07-30 Jesper Skov * ecos.db: Added Dreamcast platform HAL, contributed by Takeshi diff --git a/packages/ecos.db b/packages/ecos.db --- a/packages/ecos.db +++ b/packages/ecos.db @@ -410,7 +410,7 @@ package CYGPKG_IO_SERIAL_ARM_AT91 { hardware directory devs/serial/arm/at91 script ser_arm_at91.cdl - description "Atmel AT91 evaulation board (EB40) serial drivers." + description "Atmel AT91 evaluation board (EB40) serial drivers." } package CYGPKG_IO_SERIAL_POWERPC_COGENT { @@ -1167,7 +1167,7 @@ package CYGPKG_HAL_ARM_SA11X0_ASSABET { hardware description " The ASSABET HAL package provides the support needed to run - eCos on a Intel StrongARM SA1110 evaulation board (assabet)." + eCos on a Intel StrongARM SA1110 evaluation board (assabet)." } package CYGPKG_HAL_ARM_SA11X0_IPAQ { @@ -1226,7 +1226,7 @@ package CYGPKG_HAL_ARM_SA11X0_BRUTUS { hardware description " The BRUTUS HAL package provides the support needed to run - eCos on a Intel StrongARM SA1110 evaulation board (brutus)." + eCos on a Intel StrongARM SA1110 evaluation board (brutus)." } package CYGPKG_HAL_ARM_SA11X0_SA1100MM { @@ -1858,7 +1858,7 @@ Evaluator7T board (aka AEB-2)." } target at91 { - alias { "Atmel evaulation board (EB40)" eb40 } + alias { "Atmel evaluation board (EB40)" eb40 } packages { CYGPKG_HAL_ARM CYGPKG_HAL_ARM_AT91 CYGPKG_DEVS_FLASH_AT91 diff --git a/packages/hal/i386/arch/current/ChangeLog b/packages/hal/i386/arch/current/ChangeLog --- a/packages/hal/i386/arch/current/ChangeLog +++ b/packages/hal/i386/arch/current/ChangeLog @@ -1,3 +1,7 @@ +2001-07-31 Jonathan Larmour + + * src/hal_misc.c: Fix "implicit decl of diag_printf" warning. + 2001-07-13 Nick Garnett * include/arch.inc: diff --git a/packages/hal/i386/arch/current/src/hal_misc.c b/packages/hal/i386/arch/current/src/hal_misc.c --- a/packages/hal/i386/arch/current/src/hal_misc.c +++ b/packages/hal/i386/arch/current/src/hal_misc.c @@ -46,6 +46,7 @@ #include #include +#include // diag_printf #include diff --git a/packages/hal/i386/pcmb/current/ChangeLog b/packages/hal/i386/pcmb/current/ChangeLog --- a/packages/hal/i386/pcmb/current/ChangeLog +++ b/packages/hal/i386/pcmb/current/ChangeLog @@ -1,3 +1,8 @@ +2001-07-31 Mark Salter + + * include/pcmb_io.h: Add IDE I/O macros. + * cdl/hal_i386_pcmb.cdl: Now implements CYGINT_HAL_PLF_IF_IDE. + 2001-07-18 Jonathan Larmour * include/pcmb_intr.h: Fill in interrupt table descriptions. diff --git a/packages/hal/i386/pcmb/current/cdl/hal_i386_pcmb.cdl b/packages/hal/i386/pcmb/current/cdl/hal_i386_pcmb.cdl --- a/packages/hal/i386/pcmb/current/cdl/hal_i386_pcmb.cdl +++ b/packages/hal/i386/pcmb/current/cdl/hal_i386_pcmb.cdl @@ -59,6 +59,7 @@ cdl_package CYGPKG_HAL_I386_PCMB { compile pcmb_misc.c pcmb_serial.c implements CYGINT_HAL_I386_MEM_REAL_REGION_TOP + implements CYGINT_HAL_PLF_IF_IDE # Real-time clock/counter specifics cdl_component CYGNUM_HAL_RTC_CONSTANTS { diff --git a/packages/hal/i386/pcmb/current/include/pcmb_io.h b/packages/hal/i386/pcmb/current/include/pcmb_io.h --- a/packages/hal/i386/pcmb/current/include/pcmb_io.h +++ b/packages/hal/i386/pcmb/current/include/pcmb_io.h @@ -26,7 +26,7 @@ // // The Initial Developer of the Original Code is Red Hat. // Portions created by Red Hat are -// Copyright (C) 1998, 1999, 2000 Red Hat, Inc. +// Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc. // All Rights Reserved. // ------------------------------------------- // @@ -193,5 +193,36 @@ CYG_MACRO_END PC_WRITE_SCREEN_16( (__pos)+4, __val ); //----------------------------------------------------------------------------- +// IDE interface macros +// +#define HAL_IDE_NUM_CONTROLLERS 2 + +// Initialize the IDE controller(s). +#define HAL_IDE_INIT() + +#define __PCMB_IDE_PRI_CMD 0x1f0 +#define __PCMB_IDE_PRI_CTL 0x3f4 +#define __PCMB_IDE_SEC_CMD 0x170 +#define __PCMB_IDE_SEC_CTL 0x374 + +#define __CMD_ADDR(__n) ((__n) ? __PCMB_IDE_SEC_CMD : __PCMB_IDE_PRI_CMD) +#define __CTL_ADDR(__n) ((__n) ? __PCMB_IDE_SEC_CTL : __PCMB_IDE_PRI_CTL) + +#define HAL_IDE_READ_UINT8( __ctlr, __regno, __val ) \ + HAL_READ_UINT8(__CMD_ADDR(__ctlr) + (__regno), (__val)) +#define HAL_IDE_READ_UINT16( __ctlr, __regno, __val ) \ + HAL_READ_UINT16(__CMD_ADDR(__ctlr) + (__regno), (__val)) +#define HAL_IDE_READ_ALTSTATUS( __ctlr, __val ) \ + HAL_READ_UINT16(__CTL_ADDR(__ctlr), (__val)) + +#define HAL_IDE_WRITE_UINT8( __ctlr, __regno, __val ) \ + HAL_WRITE_UINT8(__CMD_ADDR(__ctlr) + (__regno), (__val)) +#define HAL_IDE_WRITE_UINT16( __ctlr, __regno, __val ) \ + HAL_WRITE_UINT16(__CMD_ADDR(__ctlr) + (__regno), (__val)) +#define HAL_IDE_WRITE_CONTROL( __ctlr, __val ) \ + HAL_WRITE_UINT16(__CTL_ADDR(__ctlr), (__val)) + + +//----------------------------------------------------------------------------- // end of pcmb_io.h #endif // CYGONCE_PCMB_IO_H diff --git a/packages/hal/mips/arch/current/ChangeLog b/packages/hal/mips/arch/current/ChangeLog --- a/packages/hal/mips/arch/current/ChangeLog +++ b/packages/hal/mips/arch/current/ChangeLog @@ -1,3 +1,17 @@ +2001-08-01 Hugo Tyson + + * src/vectors.S (restore_state): (see the change below 2001-07-03) + Make the code to keep SR IM bits from the ISR conditional on a CDL + interface so that it is selected on a per-platform or variant basis. + + * cdl/hal_mips.cdl (CYGINT_HAL_MIPS_INTERRUPT_RETURN_KEEP_SR_IM): + New interface to control conditional code. + + * include/hal_intr.h (HAL_ENABLE_INTERRUPTS): Make this (et al) + conditional on CYGHWR_HAL_INTERRUPT_ENABLE_DISABLE_RESTORE_DEFINED + so that the variant HAL can define these insead, in the usual + manner. + 2001-07-20 Jonathan Larmour * src/redboot_linux_exec.c: Adjust below change by getting baud diff --git a/packages/hal/mips/arch/current/cdl/hal_mips.cdl b/packages/hal/mips/arch/current/cdl/hal_mips.cdl --- a/packages/hal/mips/arch/current/cdl/hal_mips.cdl +++ b/packages/hal/mips/arch/current/cdl/hal_mips.cdl @@ -115,6 +115,20 @@ cdl_package CYGPKG_HAL_MIPS { been compiled as 32-bit. Do not use this for real 64-bit code." } + cdl_interface CYGINT_HAL_MIPS_INTERRUPT_RETURN_KEEP_SR_IM { + display "Interrupt return keeps interrupt mask bits in SR" + description " + On some MIPS variants, the status register (SR) contains a number + of interrupt mask bits (IM\[0..7\]). Default behavior is to restore + the whole SR over an interrupt. This means that if the ISR + modifies those bits, the change is lost when the interrupt returns. + If this interface is implemented, changes made to the SR IM bits by + an ISR will instead be preserved. + Variants whose HAL_INTERRUPT_MASK() routines (et al) modify the IM + bits in the SR should implement this interface to get the necessary + preserving behavior." + } + cdl_component CYGPKG_REDBOOT_MIPS_OPTIONS { display "Redboot for MIPS options" flavor none diff --git a/packages/hal/mips/arch/current/include/hal_intr.h b/packages/hal/mips/arch/current/include/hal_intr.h --- a/packages/hal/mips/arch/current/include/hal_intr.h +++ b/packages/hal/mips/arch/current/include/hal_intr.h @@ -208,6 +208,7 @@ typedef cyg_uint32 CYG_INTERRUPT_STATE; // Beware of nops in this code. They fill delay slots and avoid CP0 hazards // that might otherwise cause following code to run in the wrong state or // cause a resource conflict. +#ifndef CYGHWR_HAL_INTERRUPT_ENABLE_DISABLE_RESTORE_DEFINED #define HAL_DISABLE_INTERRUPTS(_old_) \ { \ @@ -262,6 +263,8 @@ typedef cyg_uint32 CYG_INTERRUPT_STATE; ); \ } +#endif // CYGHWR_HAL_INTERRUPT_ENABLE_DISABLE_RESTORE_DEFINED + //-------------------------------------------------------------------------- // Routine to execute DSRs using separate interrupt stack diff --git a/packages/hal/mips/arch/current/src/vectors.S b/packages/hal/mips/arch/current/src/vectors.S --- a/packages/hal/mips/arch/current/src/vectors.S +++ b/packages/hal/mips/arch/current/src/vectors.S @@ -722,7 +722,8 @@ restore_state: #endif lw k1,mipsreg_sr(sp) # K1 = saved SR -#ifndef CYG_HAL_MIPS_R3900 + +#if 0 < CYGINT_HAL_MIPS_INTERRUPT_RETURN_KEEP_SR_IM # Keep the current settings of the IM[7:0] bits within the status # register. These may be used as interrupt masks, so if an ISR or # DSR masks interrupts they must be preserved. @@ -736,7 +737,7 @@ restore_state: nop andi k0,k0,0xff00 # preserve interrupt set or k1,k1,k0 # insert into "saved SR" -#endif +#endif // 0 < CYGINT_HAL_MIPS_INTERRUPT_RETURN_KEEP_SR_IM lva k0,mipsreg_pc(sp) # K0 = return PC lsp sp,sp # load SP diff --git a/packages/hal/synth/arch/current/ChangeLog b/packages/hal/synth/arch/current/ChangeLog --- a/packages/hal/synth/arch/current/ChangeLog +++ b/packages/hal/synth/arch/current/ChangeLog @@ -1,3 +1,10 @@ +2001-08-02 Bart Veer + + * include/hal_intr.h: + Note a subtle interaction between the interrupt handling + and the context switch handling, which are in the + architectural and variant HAL packages respectively. + 2001-04-27 Bart Veer * All files diff --git a/packages/hal/synth/arch/current/include/hal_intr.h b/packages/hal/synth/arch/current/include/hal_intr.h --- a/packages/hal/synth/arch/current/include/hal_intr.h +++ b/packages/hal/synth/arch/current/include/hal_intr.h @@ -106,7 +106,10 @@ // higher priority. There is one exception: the sequence // disable_interrupts() followed by restore_interrupts() occurs // frequently and is worth some inlining. -// macro. +// +// Note: some of the details such as the existence of a global +// variable hal_interrupts_enabled are known to the context switch +// code in the variant HAL. typedef cyg_bool_t CYG_INTERRUPT_STATE; externC volatile cyg_bool_t hal_interrupts_enabled; externC void hal_enable_interrupts(void); diff --git a/packages/hal/synth/i386linux/current/ChangeLog b/packages/hal/synth/i386linux/current/ChangeLog --- a/packages/hal/synth/i386linux/current/ChangeLog +++ b/packages/hal/synth/i386linux/current/ChangeLog @@ -1,3 +1,12 @@ +2001-08-02 Bart Veer + + * src/context.S, include/arch.inc, include/var_arch.h: + Update thread context manipulation code to do the + right thing with respect to interrupt state. + + * src/context.S (hal_setjmp): + Fixed bug in hal_setjmp() that corrupted EBX. + 2001-04-27 Bart Veer * All files diff --git a/packages/hal/synth/i386linux/current/include/arch.inc b/packages/hal/synth/i386linux/current/include/arch.inc --- a/packages/hal/synth/i386linux/current/include/arch.inc +++ b/packages/hal/synth/i386linux/current/include/arch.inc @@ -61,7 +61,8 @@ .equ i386reg_ebx, 12 .equ i386reg_esi, 16 .equ i386reg_edi, 20 - .equ i386reg_context_size, 24 + .equ i386reg_interrupts, 24 + .equ i386reg_context_size, 28 #------------------------------------------------------------------------------ # end of arch.inc diff --git a/packages/hal/synth/i386linux/current/include/var_arch.h b/packages/hal/synth/i386linux/current/include/var_arch.h --- a/packages/hal/synth/i386linux/current/include/var_arch.h +++ b/packages/hal/synth/i386linux/current/include/var_arch.h @@ -60,6 +60,7 @@ typedef struct cyg_uint32 ebx; cyg_uint32 esi; cyg_uint32 edi; + cyg_bool interrupts; // Are interrupts enabled for this thread? } HAL_SavedRegisters; @@ -117,6 +118,7 @@ CYG_MACRO_END _regs_->ebp = (CYG_WORD)(_id_); \ _regs_->esi = (CYG_WORD)(_id_); \ _regs_->edi = (CYG_WORD)(_id_); \ + _regs_->interrupts = true; \ (_sparg_) = (CYG_ADDRESS) _regs_; \ CYG_MACRO_END diff --git a/packages/hal/synth/i386linux/current/src/context.S b/packages/hal/synth/i386linux/current/src/context.S --- a/packages/hal/synth/i386linux/current/src/context.S +++ b/packages/hal/synth/i386linux/current/src/context.S @@ -78,7 +78,10 @@ name: # : 8(%esp) : address of sp save location of current thread # # %eax, %ecx, and %edx are ours to abuse. - + + .extern hal_interrupts_enabled + .extern hal_enable_interrupts + FUNC_START(hal_thread_switch_context) movl 4(%esp),%eax # next context ptr movl 8(%esp),%edx # this context ptr @@ -98,7 +101,11 @@ FUNC_START(hal_thread_switch_context) movl %ebx,i386reg_ebx(%esp) movl %esi,i386reg_esi(%esp) movl %edi,i386reg_edi(%esp) - + + # And interrupt state + movl hal_interrupts_enabled,%eax + movl %eax,i386reg_interrupts(%esp) + # Store the context ptr movl %esp,(%edx) @@ -126,6 +133,21 @@ FUNC_START(hal_thread_load_context) movl i386reg_edi(%eax),%edi movl i386reg_esp(%eax),%esp + # And see what needs to happen about interrupts + movl i386reg_interrupts(%eax),%eax + cmpl hal_interrupts_enabled,%eax + je interrupts_ok + + # The saved interrupt state differs from the current one. + # If interrupts are supposed to be enabled then invoke + # hal_enable_interrupts. That can be done as a tail call. + # If interrupts are supposed to be disabled then just + # update the global variable. + cmpl $0,%eax + jne hal_enable_interrupts + movl %eax,hal_interrupts_enabled + +interrupts_ok: ret @@ -157,8 +179,8 @@ FUNC_START(hal_setjmp) # Stack and PC movl %esp,CYGARC_JMP_BUF_SP*4(%eax) - movl 0(%esp),%ebx - movl %ebx,CYGARC_JMP_BUF_PC*4(%eax) + movl 0(%esp),%edx + movl %edx,CYGARC_JMP_BUF_PC*4(%eax) # Return 0 xor %eax,%eax diff --git a/packages/net/tcpip/current/ChangeLog b/packages/net/tcpip/current/ChangeLog --- a/packages/net/tcpip/current/ChangeLog +++ b/packages/net/tcpip/current/ChangeLog @@ -1,3 +1,13 @@ +2001-08-02 Jonathan Larmour + + * tests/linux_echo.c (echo_test): Set socket options before bind. + * tests/nc_test_slave.c (do_tcp_test): Ditto. + * tests/server_test.c (server_test): Ditto. + * tests/tcp_echo.c (echo_test): Ditto. + * tests/tcp_lo_test.c (server): Ditto. + * tests/tcp_sink.c (sink_test): Ditto. + * tests/tcp_source.c (source_test): Ditto. + 2001-07-27 Jonathan Larmour * include/sys/select.h: Renamed to.... diff --git a/packages/net/tcpip/current/tests/linux_echo.c b/packages/net/tcpip/current/tests/linux_echo.c --- a/packages/net/tcpip/current/tests/linux_echo.c +++ b/packages/net/tcpip/current/tests/linux_echo.c @@ -172,6 +172,9 @@ echo_test(void * p) if (s_source < 0) { pexit("stream socket"); } + if (setsockopt(s_source, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) { + pexit("setsockopt /source/ SO_REUSEADDR"); + } memset(&local, 0, sizeof(local)); local.sin_family = AF_INET; // local.sin_len = sizeof(local); @@ -180,9 +183,6 @@ echo_test(void * p) if(bind(s_source, (struct sockaddr *) &local, sizeof(local)) < 0) { pexit("bind /source/ error"); } - if (setsockopt(s_source, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) { - pexit("setsockopt /source/ SO_REUSEADDR"); - } listen(s_source, SOMAXCONN); s_sink = socket(AF_INET, SOCK_STREAM, 0); diff --git a/packages/net/tcpip/current/tests/nc_test_slave.c b/packages/net/tcpip/current/tests/nc_test_slave.c --- a/packages/net/tcpip/current/tests/nc_test_slave.c +++ b/packages/net/tcpip/current/tests/nc_test_slave.c @@ -324,15 +324,6 @@ do_tcp_test(int s1, struct nc_request *r pexit("datagram socket"); } - memset((char *) &test_chan_slave, 0, sizeof(test_chan_slave)); - test_chan_slave.sin_family = AF_INET; - test_chan_slave.sin_addr.s_addr = htonl(INADDR_ANY); - test_chan_slave.sin_port = htons(ntohl(req->slave_port)); - - if (bind(s, (struct sockaddr *) &test_chan_slave, sizeof(test_chan_slave)) < 0) { - perror("bind"); - close(s); - } if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) { perror("setsockopt SO_REUSEADDR"); return; @@ -343,6 +334,15 @@ do_tcp_test(int s1, struct nc_request *r return; } #endif + memset((char *) &test_chan_slave, 0, sizeof(test_chan_slave)); + test_chan_slave.sin_family = AF_INET; + test_chan_slave.sin_addr.s_addr = htonl(INADDR_ANY); + test_chan_slave.sin_port = htons(ntohl(req->slave_port)); + + if (bind(s, (struct sockaddr *) &test_chan_slave, sizeof(test_chan_slave)) < 0) { + perror("bind"); + close(s); + } listen(s, SOMAXCONN); slave_tcp_port = s; } diff --git a/packages/net/tcpip/current/tests/server_test.c b/packages/net/tcpip/current/tests/server_test.c --- a/packages/net/tcpip/current/tests/server_test.c +++ b/packages/net/tcpip/current/tests/server_test.c @@ -90,6 +90,12 @@ server_test(struct bootp *bp) if (s < 0) { pexit("stream socket"); } + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) { + pexit("setsockopt SO_REUSEADDR"); + } + if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one))) { + pexit("setsockopt SO_REUSEPORT"); + } memset(&local, 0, sizeof(local)); local.sin_family = AF_INET; local.sin_len = sizeof(local); @@ -98,12 +104,6 @@ server_test(struct bootp *bp) if(bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) { pexit("bind error"); } - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) { - pexit("setsockopt SO_REUSEADDR"); - } - if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one))) { - pexit("setsockopt SO_REUSEPORT"); - } listen(s, SOMAXCONN); while (true) { client_len = sizeof(client_addr); diff --git a/packages/net/tcpip/current/tests/tcp_echo.c b/packages/net/tcpip/current/tests/tcp_echo.c --- a/packages/net/tcpip/current/tests/tcp_echo.c +++ b/packages/net/tcpip/current/tests/tcp_echo.c @@ -388,6 +388,12 @@ echo_test(cyg_addrword_t p) if (s_source < 0) { pexit("stream socket"); } + if (setsockopt(s_source, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) { + pexit("setsockopt /source/ SO_REUSEADDR"); + } + if (setsockopt(s_source, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one))) { + pexit("setsockopt /source/ SO_REUSEPORT"); + } memset(&local, 0, sizeof(local)); local.sin_family = AF_INET; local.sin_len = sizeof(local); @@ -396,12 +402,6 @@ echo_test(cyg_addrword_t p) if(bind(s_source, (struct sockaddr *) &local, sizeof(local)) < 0) { pexit("bind /source/ error"); } - if (setsockopt(s_source, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) { - pexit("setsockopt /source/ SO_REUSEADDR"); - } - if (setsockopt(s_source, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one))) { - pexit("setsockopt /source/ SO_REUSEPORT"); - } listen(s_source, SOMAXCONN); s_sink = socket(AF_INET, SOCK_STREAM, 0); diff --git a/packages/net/tcpip/current/tests/tcp_lo_test.c b/packages/net/tcpip/current/tests/tcp_lo_test.c --- a/packages/net/tcpip/current/tests/tcp_lo_test.c +++ b/packages/net/tcpip/current/tests/tcp_lo_test.c @@ -95,6 +95,12 @@ void server(void) if (s_source < 0) { pexit("stream socket"); } + if (setsockopt(s_source, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) { + pexit("setsockopt /source/ SO_REUSEADDR"); + } + if (setsockopt(s_source, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one))) { + pexit("setsockopt /source/ SO_REUSEPORT"); + } memset(&local, 0, sizeof(local)); local.sin_family = AF_INET; local.sin_len = sizeof(local); @@ -103,12 +109,6 @@ void server(void) if(bind(s_source, (struct sockaddr *) &local, sizeof(local)) < 0) { pexit("bind /source/ error"); } - if (setsockopt(s_source, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) { - pexit("setsockopt /source/ SO_REUSEADDR"); - } - if (setsockopt(s_source, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one))) { - pexit("setsockopt /source/ SO_REUSEPORT"); - } listen(s_source, SOMAXCONN); e_source = 0; diff --git a/packages/net/tcpip/current/tests/tcp_sink.c b/packages/net/tcpip/current/tests/tcp_sink.c --- a/packages/net/tcpip/current/tests/tcp_sink.c +++ b/packages/net/tcpip/current/tests/tcp_sink.c @@ -194,6 +194,9 @@ sink_test(char *echo_node) if (s_sink < 0) { pexit("stream socket"); } + if (setsockopt(s_sink, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) { + pexit("setsockopt /sink/ SO_REUSEADDR"); + } memset(&local, 0, sizeof(local)); local.sin_family = AF_INET; local.sin_port = INADDR_ANY; @@ -201,9 +204,6 @@ sink_test(char *echo_node) if(bind(s_sink, (struct sockaddr *) &local, sizeof(local)) < 0) { pexit("bind /sink/ error"); } - if (setsockopt(s_sink, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) { - pexit("setsockopt /sink/ SO_REUSEADDR"); - } if (connect(s_sink, (struct sockaddr *)&slave, sizeof(slave)) < 0) { pexit("Can't connect to target"); diff --git a/packages/net/tcpip/current/tests/tcp_source.c b/packages/net/tcpip/current/tests/tcp_source.c --- a/packages/net/tcpip/current/tests/tcp_source.c +++ b/packages/net/tcpip/current/tests/tcp_source.c @@ -196,6 +196,9 @@ source_test(char *echo_node, int load) if (s_source < 0) { pexit("stream socket"); } + if (setsockopt(s_source, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) { + pexit("setsockopt /source/ SO_REUSEADDR"); + } memset(&local, 0, sizeof(local)); local.sin_family = AF_INET; local.sin_port = INADDR_ANY; @@ -203,9 +206,6 @@ source_test(char *echo_node, int load) if(bind(s_source, (struct sockaddr *) &local, sizeof(local)) < 0) { pexit("bind /source/ error"); } - if (setsockopt(s_source, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) { - pexit("setsockopt /source/ SO_REUSEADDR"); - } if (connect(s_source, (struct sockaddr *)&slave, sizeof(slave)) < 0) { pexit("Can't connect to target"); diff --git a/packages/pkgconf/rules.mak b/packages/pkgconf/rules.mak --- a/packages/pkgconf/rules.mak +++ b/packages/pkgconf/rules.mak @@ -23,7 +23,7 @@ # # The Initial Developer of the Original Code is Red Hat. # Portions created by Red Hat are -# Copyright (C) 1998, 1999, 2000 Red Hat, Inc. +# Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc. # All Rights Reserved. # ------------------------------------------- # @@ -91,7 +91,7 @@ else @mkdir -p $(dir $@) endif $(CC) -c $(INCLUDE_PATH) -I$(dir $<) $(CFLAGS) -Wp,-MD,$(@:.d=.tmp) -o $(@:.d=.o) $< - @sed -e '/^ *\\/d' -e "s#.*: #$@: #" $(@:.o.d=.tmp) > $@ + @sed -e '/^ *\\/d' -e "s#.*: #$@: #" $(@:.d=.tmp) > $@ @rm $(@:.d=.tmp) %.d : %.cxx @@ -101,7 +101,7 @@ else @mkdir -p $(dir $@) endif $(CC) -c $(INCLUDE_PATH) -I$(dir $<) $(CFLAGS) -Wp,-MD,$(@:.d=.tmp) -o $(@:.d=.o) $< - @sed -e '/^ *\\/d' -e "s#.*: #$@: #" $(@:.o.d=.tmp) > $@ + @sed -e '/^ *\\/d' -e "s#.*: #$@: #" $(@:.d=.tmp) > $@ @rm $(@:.d=.tmp) %.d : %.S @@ -111,7 +111,7 @@ else @mkdir -p $(dir $@) endif $(CC) -c $(INCLUDE_PATH) -I$(dir $<) $(CFLAGS) -Wp,-MD,$(@:.d=.tmp) -o $(@:.d=.o) $< - @sed -e '/^ *\\/d' -e "s#.*: #$@: #" $(@:.o.d=.tmp) > $@ + @sed -e '/^ *\\/d' -e "s#.*: #$@: #" $(@:.d=.tmp) > $@ @rm $(@:.d=.tmp) # rule to generate a test executable from object code diff --git a/packages/redboot/current/ChangeLog b/packages/redboot/current/ChangeLog --- a/packages/redboot/current/ChangeLog +++ b/packages/redboot/current/ChangeLog @@ -1,3 +1,14 @@ +2001-08-01 Mark Salter + + * src/fs/ide.c (ide_reset): Check for bogus status and timeout. Add + return value to indicate success. + (ide_init): Check ide_reset() return value. + +2001-07-31 Mark Salter + + * src/fs/disk.c (find_dos_partitions): Fix extended partitions. + * src/fs/ide.c (ide_init): Rework the test for device presence. + 2001-07-27 Gary Thomas * src/load.c (load_srec_image, do_load): diff --git a/packages/redboot/current/src/fs/disk.c b/packages/redboot/current/src/fs/disk.c --- a/packages/redboot/current/src/fs/disk.c +++ b/packages/redboot/current/src/fs/disk.c @@ -92,24 +92,30 @@ find_dos_partitions(disk_t *d, cyg_uint8 #if CYGNUM_REDBOOT_MAX_PARTITIONS > 4 { - cyg_uint32 buf[SECTOR_SIZE/sizeof(cyg_uint32)]; + cyg_uint32 buf[SECTOR_SIZE/sizeof(cyg_uint32)], xoffset; cyg_uint16 magic; - int j, nextp; + int nextp; // Go back through and find extended partitions for (i = 0, nextp = 4; i < 4 && nextp < CYGNUM_REDBOOT_MAX_PARTITIONS; i++) { if (d->partitions[i].systype == SYSTYPE_EXTENDED) { - // read partition boot record (same format as mbr) - if (DISK_READ(d, d->partitions[i].start_sector, buf, 1) <= 0) - break; + // sector offsets in partition tables are relative to start + // of extended partition. + xoffset = d->partitions[i].start_sector; + for ( ; nextp < CYGNUM_REDBOOT_MAX_PARTITIONS; ++nextp) { - magic = *(cyg_uint16 *)((char *)buf + MBR_MAGIC_OFFSET); - if (SWAB_LE16(magic) != MBR_MAGIC) - continue; + // read partition boot record (same format as mbr except + // there should only be 2 entries max: a normal partition + // and another extended partition + if (DISK_READ(d, xoffset, buf, 1) <= 0) + break; - p = (struct mbr_partition *)(buf + MBR_PTABLE_OFFSET); + magic = *(cyg_uint16 *)((char *)buf + MBR_MAGIC_OFFSET); + if (SWAB_LE16(magic) != MBR_MAGIC) + break; - for (j = 0; i < 4 && nextp < CYGNUM_REDBOOT_MAX_PARTITIONS; j++, nextp++) { + p = (struct mbr_partition *)((char *)buf + MBR_PTABLE_OFFSET); + // Have to use memcpy because of alignment memcpy(&tmp, p->start_sect, 4); s = SWAB_LE32(tmp); @@ -119,18 +125,28 @@ find_dos_partitions(disk_t *d, cyg_uint8 if (s && n) { ++found; d->partitions[nextp].disk = d; - d->partitions[nextp].start_sector = s + d->partitions[i].start_sector; + d->partitions[nextp].start_sector = s + xoffset; d->partitions[nextp].nr_sectors = n; d->partitions[nextp].systype = p->sys_ind; d->partitions[nextp].bootflag = p->boot_ind; } ++p; + + memcpy(&tmp, p->start_sect, 4); + s = SWAB_LE32(tmp); + memcpy(&tmp, p->nr_sects, 4); + n = SWAB_LE32(tmp); + + // more extended partitions? + if (p->sys_ind != SYSTYPE_EXTENDED || !s || !n) + break; + + xoffset += s; } } } } #endif - return found; } diff --git a/packages/redboot/current/src/fs/ide.c b/packages/redboot/current/src/fs/ide.c --- a/packages/redboot/current/src/fs/ide.c +++ b/packages/redboot/current/src/fs/ide.c @@ -81,14 +81,28 @@ static inline int return 0; } -static void +static int ide_reset(int ctlr) { + cyg_uint8 status; + int delay; + HAL_IDE_WRITE_CONTROL(ctlr, 6); // polled mode, reset asserted CYGACC_CALL_IF_DELAY_US(5000); HAL_IDE_WRITE_CONTROL(ctlr, 2); // polled mode, reset cleared CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000); - __wait_for_ready(ctlr); + + // wait 30 seconds max for not busy + for (delay = 0; delay < 300; ++delay) { + CYGACC_CALL_IF_DELAY_US((cyg_uint32)100000); + HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status); + // bail out early on bogus status + if ((status & (IDE_STAT_BSY|IDE_STAT_DRDY)) == (IDE_STAT_BSY|IDE_STAT_DRDY)) + break; + if (!(status & IDE_STAT_BSY)) + return 1; + } + return 0; } static int @@ -98,16 +112,10 @@ ide_ident(int ctlr, int dev, int is_pack HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, dev << 4); HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, is_packet_dev ? 0xA1 : 0xEC); - - if (!__wait_for_drq(ctlr)) { - cyg_uint8 status; + CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000); - HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status); - - printf("%s: NO DRQ for ide%d, device %d. status[%02x]\n", - __FUNCTION__, ctlr, dev, status); + if (!__wait_for_drq(ctlr)) return 0; - } for (i = 0; i < (SECTOR_SIZE / sizeof(cyg_uint16)); i++, buf++) HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *buf); @@ -157,14 +165,15 @@ ide_read(struct disk *d, static void ide_init(void) { - cyg_uint32 buf[SECTOR_SIZE/sizeof(cyg_uint32)]; - cyg_uint32 u32; + cyg_uint32 buf[SECTOR_SIZE/sizeof(cyg_uint32)], u32; cyg_uint16 u16; - cyg_uint8 sig[2][4]; + cyg_uint8 u8; int i, j; disk_t disk; struct ide_priv *priv; +#define DEV_INIT_VAL ((j << 4) | 0xA0) + HAL_IDE_INIT(); CYGACC_CALL_IF_DELAY_US(5); @@ -173,19 +182,8 @@ ide_init(void) for (i = 0; i < HAL_IDE_NUM_CONTROLLERS; i++) { // soft reset the devices on this controller - ide_reset(i); - - // save off signature values for later - HAL_IDE_WRITE_UINT8(i, IDE_REG_DEVICE, (0 << 4)); - HAL_IDE_READ_UINT8(i, IDE_REG_COUNT, sig[0][0]); - HAL_IDE_READ_UINT8(i, IDE_REG_LBALOW, sig[0][1]); - HAL_IDE_READ_UINT8(i, IDE_REG_LBAMID, sig[0][2]); - HAL_IDE_READ_UINT8(i, IDE_REG_LBAHI, sig[0][3]); - HAL_IDE_WRITE_UINT8(i, IDE_REG_DEVICE, (1 << 4)); - HAL_IDE_READ_UINT8(i, IDE_REG_COUNT, sig[1][0]); - HAL_IDE_READ_UINT8(i, IDE_REG_LBALOW, sig[1][1]); - HAL_IDE_READ_UINT8(i, IDE_REG_LBAMID, sig[1][2]); - HAL_IDE_READ_UINT8(i, IDE_REG_LBAHI, sig[1][3]); + if (!ide_reset(i)) + continue; // 2 devices per controller for (j = 0; j < 2; j++, priv++) { @@ -193,23 +191,30 @@ ide_init(void) priv->controller = i; priv->drive = j; priv->flags = 0; - - if (sig[j][0] != 0x01 || sig[j][1] != 0x01) - continue; - - if (!(sig[j][2] == 0x00 && sig[j][3] == 0x00) && - !(sig[j][2] == 0x14 && sig[j][3] == 0xeb)) + + // This is reminiscent of a memory test. We write a value + // to a certain location (device register), then write a + // different value somewhere else so that the first value + // is not hanging on the bus, then we read back the first + // value to see if the write was succesful. + // + HAL_IDE_WRITE_UINT8(i, IDE_REG_DEVICE, DEV_INIT_VAL); + HAL_IDE_WRITE_UINT8(i, IDE_REG_FEATURES, 0); + CYGACC_CALL_IF_DELAY_US(50000); + HAL_IDE_READ_UINT8(i, IDE_REG_DEVICE, u8); + if (u8 != DEV_INIT_VAL) continue; // device present - - priv->flags = IDE_DEV_PRESENT; + priv->flags |= IDE_DEV_PRESENT; - if (sig[j][2] == 0x14 && sig[j][3] == 0xeb) - priv->flags |= IDE_DEV_PACKET; - - if (ide_ident(i, j, priv->flags & IDE_DEV_PACKET, (cyg_uint16 *)buf) <= 0) - continue; + if (ide_ident(i, j, 0, (cyg_uint16 *)buf) <= 0) { + if (ide_ident(i, j, 1, (cyg_uint16 *)buf) <= 0) { + priv->flags = 0; + continue; // can't identify device + } else + priv->flags |= IDE_DEV_PACKET; + } memset(&disk, 0, sizeof(disk)); disk.funs = &ide_funs; diff --git a/packages/services/memalloc/common/current/ChangeLog b/packages/services/memalloc/common/current/ChangeLog --- a/packages/services/memalloc/common/current/ChangeLog +++ b/packages/services/memalloc/common/current/ChangeLog @@ -1,3 +1,20 @@ +2001-08-01 Jonathan Larmour + + * include/sepmetaimpl.inl: Define check_free_memdq and + check_alloced_memdq as inlines. + + * cdl/memalloc.cdl: Add new allocator supporting separate metadata, + and the associated config options, and build sepmeta.cxx and tests. + Build heapgeninc.tcl with macros that work with both gcc2 and gcc3. + Ditto for heaps.o. + Add CYGBLD_MEMALLOC_MALLOC_EXTERNAL_HEAP_H to allow external entities + to define the heap. + * src/malloc.cxx: Include CYGBLD_MEMALLOC_MALLOC_EXTERNAL_HEAP_H if + defined instead of default heap definition. + * include/sepmeta.hxx, include/sepmetaimpl.hxx, include/sepmetaimpl.inl, + src/sepmeta.cxx, tests/sepmeta1.cxx, tests/sepmeta2.cxx: + New files for seperated metadata allocator. + 2001-07-18 Jonathan Larmour * src/heapgen.tcl: Use constructor priority of CYG_INIT_MEMALLOC diff --git a/packages/services/memalloc/common/current/cdl/memalloc.cdl b/packages/services/memalloc/common/current/cdl/memalloc.cdl --- a/packages/services/memalloc/common/current/cdl/memalloc.cdl +++ b/packages/services/memalloc/common/current/cdl/memalloc.cdl @@ -46,7 +46,8 @@ cdl_package CYGPKG_MEMALLOC { dynamic memory allocators, including the ISO standard malloc interface. It also contains some sample implementations." include_dir cyg/memalloc - compile dlmalloc.cxx kapi.cxx malloc.cxx memfixed.cxx memvar.cxx + compile dlmalloc.cxx kapi.cxx malloc.cxx memfixed.cxx memvar.cxx \ + sepmeta.cxx # ==================================================================== @@ -175,6 +176,26 @@ cdl_package CYGPKG_MEMALLOC { are faster in some circumstances." } } + + cdl_component CYGPKG_MEMALLOC_ALLOCATOR_SEPMETA { + display "Variable block allocator with separate metadata" + flavor none + no_define + description " + This component contains configuration options related to the + variable block memory allocator with separate metadata." + + cdl_option CYGSEM_MEMALLOC_ALLOCATOR_SEPMETA_THREADAWARE { + display "Make thread safe" + active_if CYGPKG_KERNEL + default_value 1 + description " + With this option enabled, this allocator will be + made thread-safe. Additionally allocation functions + are made available that allow a thread to wait + until memory is available." + } + } } cdl_option CYGFUN_MEMALLOC_KAPI { @@ -218,9 +239,7 @@ cdl_package CYGPKG_MEMALLOC { make -priority 50 { heapgeninc.tcl : /src/heapgen.cpp $(CC) $(CFLAGS) $(INCLUDE_PATH) -Wp,-MD,heapgen.tmp -E $< -o $@ - @echo $@ ':' $< '\' > $(notdir $@).deps - @tail +2 heapgen.tmp >> $(notdir $@).deps - @echo >> $(notdir $@).deps + @sed -e '/^ *\\/d' -e "s#.*: #$@: #" heapgen.tmp > $(notdir $@).deps @rm heapgen.tmp } @@ -239,12 +258,21 @@ cdl_package CYGPKG_MEMALLOC { make_object { heaps.o.d : heaps.cxx $(CC) $(CFLAGS) $(INCLUDE_PATH) -Wp,-MD,heaps.tmp -c -o $(OBJECT_PREFIX)_$(notdir $(@:.o.d=.o)) $< - @echo $@ ':' $< '\' > $@ - @tail +2 heaps.tmp >> $@ - @echo >> $@ + @sed -e '/^ *\\/d' -e "s#.*: #$@: #" heaps.tmp > $@ @rm heaps.tmp } + cdl_component CYGBLD_MEMALLOC_MALLOC_EXTERNAL_HEAP_H { + display "Use external heap definition" + flavor booldata + default_value 0 + description "This option allows other components in the + system to override the default system + provision of heap memory pools. This should + be set to a header which provides the equivalent + definitions to ." + } + cdl_interface CYGINT_MEMALLOC_MALLOC_ALLOCATORS { display "malloc() allocator implementations" requires { CYGINT_MEMALLOC_MALLOC_ALLOCATORS == 1 } @@ -343,7 +371,7 @@ cdl_package CYGPKG_MEMALLOC { display "Tests" flavor data no_define - calculated { "tests/dlmalloc1 tests/dlmalloc2 tests/heaptest tests/kmemfix1 tests/kmemvar1 tests/malloc1 tests/malloc2 tests/malloc3 tests/malloc4 tests/memfix1 tests/memfix2 tests/memvar1 tests/memvar2 tests/realloc" } + calculated { "tests/dlmalloc1 tests/dlmalloc2 tests/heaptest tests/kmemfix1 tests/kmemvar1 tests/malloc1 tests/malloc2 tests/malloc3 tests/malloc4 tests/memfix1 tests/memfix2 tests/memvar1 tests/memvar2 tests/realloc tests/sepmeta1 tests/sepmeta2" } description " This option specifies the set of tests for this package." } diff --git a/packages/services/memalloc/common/current/include/sepmeta.hxx b/packages/services/memalloc/common/current/include/sepmeta.hxx new file mode 100644 --- /dev/null +++ b/packages/services/memalloc/common/current/include/sepmeta.hxx @@ -0,0 +1,165 @@ +#ifndef CYGONCE_MEMALLOC_SEPMETA_HXX +#define CYGONCE_MEMALLOC_SEPMETA_HXX + +//========================================================================== +// +// sepmeta.hxx +// +// Variable block memory pool with separate metadata +// +//========================================================================== +//####COPYRIGHTBEGIN#### +// +// ------------------------------------------- +// The contents of this file are subject to the Red Hat eCos Public License +// Version 1.1 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://www.redhat.com/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations under +// the License. +// +// The Original Code is eCos - Embedded Configurable Operating System, +// released September 30, 1998. +// +// The Initial Developer of the Original Code is Red Hat. +// Portions created by Red Hat are +// Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc. +// All Rights Reserved. +// ------------------------------------------- +// +//####COPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): jlarmour +// Contributors: +// Date: 2001-06-28 +// Purpose: Define Sepmeta class interface +// Description: Inline class for constructing a variable block allocator +// with separate metadata +// Usage: #include +// +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +// CONFIGURATION + +#include +#ifdef CYGSEM_MEMALLOC_ALLOCATOR_SEPMETA_THREADAWARE +# include +# ifdef CYGPKG_KERNEL +# include +# endif +#endif + +#if 0 +// when used as an implementation for malloc, we need the following +// to let the system know the name of the class +#define CYGCLS_MEMALLOC_MALLOC_IMPL Cyg_Mempool_Sepmeta +#endif + +// if the implementation is all that's required, don't output anything else +#ifndef __MALLOC_IMPL_WANTED +// INCLUDES + +#include // types +#include // assertion macros + +#ifdef CYGFUN_KERNEL_THREADS_TIMER +# include // cyg_tick_count +#endif + +#ifdef CYGSEM_MEMALLOC_ALLOCATOR_SEPMETA_THREADAWARE +# include // kernel safe mempool template +#endif + +#include // implementation of this mem pool +#include // Common memory allocator infra + + +// TYPE DEFINITIONS + +class Cyg_Mempool_Sepmeta +{ +protected: + // This is a horrible workaround for the fact that C++ doesn't let + // you construct mypool explicitly if you have to initialize a struct + // to pass as an argument first. + struct Cyg_Mempool_Sepmeta_Implementation::constructorargs args; + +#ifdef CYGSEM_MEMALLOC_ALLOCATOR_SEPMETA_THREADAWARE + Cyg_Mempolt2 mypool; +#else + Cyg_Mempool_Sepmeta_Implementation mypool; +#endif +public: + // This API makes concrete a class which implements a thread-safe + // kernel-savvy memory pool which manages variable size blocks with + // separate metadata. + + // Constructor: gives the base and size of the arena in which memory is + // to be carved out, note that management structures are taken from the + // same arena. + Cyg_Mempool_Sepmeta( cyg_uint8 * /* base */, cyg_int32 /* size */, + cyg_int32 /* alignment */, + cyg_uint8 * /* metabase */, + cyg_uint32 /* metasize */); + + // Destructor + ~Cyg_Mempool_Sepmeta(); + + // get some memory; wait if none available + // if we aren't configured to be thread-aware this is irrelevant +#ifdef CYGSEM_MEMALLOC_ALLOCATOR_SEPMETA_THREADAWARE + cyg_uint8 * + alloc( cyg_int32 /* size */ ); + +# ifdef CYGFUN_KERNEL_THREADS_TIMER + // get some memory with a timeout + cyg_uint8 * + alloc( cyg_int32 /* size */, cyg_tick_count /* delay_timeout */ ); +# endif +#endif + + // get some memory, return NULL if none available + cyg_uint8 * + try_alloc( cyg_int32 /* size */ ); + + // resize existing allocation, if oldsize is non-NULL, previous + // allocation size is placed into it. If previous size not available, + // it is set to 0. NB previous allocation size may have been rounded up. + // Occasionally the allocation can be adjusted *backwards* as well as, + // or instead of forwards, therefore the address of the resized + // allocation is returned, or NULL if no resizing was possible. + // Note that this differs from ::realloc() in that no attempt is + // made to call malloc() if resizing is not possible - that is left + // to higher layers. The data is copied from old to new though. + // The effects of alloc_ptr==NULL or newsize==0 are undefined + cyg_uint8 * + resize_alloc( cyg_uint8 * /* alloc_ptr */, cyg_int32 /* newsize */, + cyg_int32 * /* oldsize */ =NULL ); + + // free the memory back to the pool + // returns true on success + cyg_bool + free( cyg_uint8 * /* ptr */, cyg_int32 /* size */ =0 ); + + // Get memory pool status + // flags is a bitmask of requested fields to fill in. The flags are + // defined in common.hxx + void + get_status( cyg_mempool_status_flag_t /* flags */, + Cyg_Mempool_Status & /* status */ ); + + CYGDBG_DEFINE_CHECK_THIS +}; + +#endif // ifndef __MALLOC_IMPL_WANTED + +#endif // ifndef CYGONCE_MEMALLOC_SEPMETA_HXX +// EOF sepmeta.hxx diff --git a/packages/services/memalloc/common/current/include/sepmetaimpl.hxx b/packages/services/memalloc/common/current/include/sepmetaimpl.hxx new file mode 100644 --- /dev/null +++ b/packages/services/memalloc/common/current/include/sepmetaimpl.hxx @@ -0,0 +1,185 @@ +#ifndef CYGONCE_MEMALLOC_SEPMETAIMPL_HXX +#define CYGONCE_MEMALLOC_SEPMETAIMPL_HXX + +//========================================================================== +// +// sepmetaimpl.hxx +// +// Variable block memory pool with separate metadata class declarations +// +//========================================================================== +//####COPYRIGHTBEGIN#### +// +// ------------------------------------------- +// The contents of this file are subject to the Red Hat eCos Public License +// Version 1.1 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://www.redhat.com/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations under +// the License. +// +// The Original Code is eCos - Embedded Configurable Operating System, +// released September 30, 1998. +// +// The Initial Developer of the Original Code is Red Hat. +// Portions created by Red Hat are +// Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc. +// All Rights Reserved. +// ------------------------------------------- +// +//####COPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): jlarmour +// Contributors: +// Date: 2001-06-28 +// Purpose: Define Sepmetaimpl class interface +// Description: Inline class for constructing a variable block allocator +// with separate metadata. +// Usage: #include +// +// +//####DESCRIPTIONEND#### +// +//========================================================================== + + +#include +#include +#include // Common memory allocator infra + +class Cyg_Mempool_Sepmeta_Implementation { +protected: + // these constructors are explicitly disallowed + Cyg_Mempool_Sepmeta_Implementation() {}; +// Cyg_Mempool_Sepmeta_Implementation( Cyg_Mempool_Sepmeta_Implementation &ref ) +// {}; + Cyg_Mempool_Sepmeta_Implementation & + operator=( Cyg_Mempool_Sepmeta_Implementation &ref ) + { return ref; }; + + struct memdq { + struct memdq *prev, *next; // prev/next alloced/free block + struct memdq *memprev, *memnext; // prev/next block in memory + cyg_uint8 *mem; // memory address associated with this block + }; + + struct memdq allocedhead; // list of alloced memory + struct memdq freehead; // list of free memory + struct memdq memhead; // initial block on free list + struct memdq memend; // dummy memdq indicating the end + // of memory, as if it were alloced + struct memdq *freemetahead; // unused memdq's + cyg_uint8 *obase; + cyg_int32 osize; + cyg_uint8 *metabase; + cyg_int32 metasize; + cyg_uint8 *bottom; + cyg_uint8 *top; + cyg_int32 alignment; + cyg_int32 freemem; + + // round up addresses according to required alignment of pool + cyg_uint8 * + alignup( cyg_uint8 *addr ); + + cyg_uint8 * + aligndown( cyg_uint8 *addr ); + + // round up addresses according to required alignment of metadata + cyg_uint8 * + alignmetaup( cyg_uint8 *addr ); + + cyg_uint8 * + alignmetadown( cyg_uint8 *addr ); + + // return the alloced dq at mem + struct memdq * + find_alloced_dq( cyg_uint8 *mem ); + + // returns a free dq of at least size, or NULL if none + struct memdq * + find_free_dq( cyg_int32 size ); + + // returns the free dq following mem + struct memdq * + find_free_dq_slot( cyg_uint8 *mem ); + + void + insert_free_block( struct memdq *freedq ); + + static void + copy_data( cyg_uint8 *dst, cyg_uint8 *src, cyg_int32 nbytes ); + + void + check_free_memdq( struct memdq *dq ); + + void + check_alloced_memdq( struct memdq *dq ); + +public: + // THIS is the public API of memory pools generally that can have the + // kernel oriented thread-safe package layer atop. + + struct constructorargs { + cyg_int32 alignment; + cyg_uint8 *metabase; + cyg_uint32 metasize; + constructorargs(cyg_int32 align, cyg_uint8 *mbase, cyg_uint32 msize) + { + alignment = align; metabase = mbase; metasize = msize; + } + }; + + // Constructor: gives the base and size of the arena in which memory is + // to be carved out. + Cyg_Mempool_Sepmeta_Implementation( + cyg_uint8 * /* base */, + cyg_int32 /* size */, + CYG_ADDRWORD /* constructorargs */ ); + + // Destructor + ~Cyg_Mempool_Sepmeta_Implementation(); + + // get size bytes of memory + cyg_uint8 * + try_alloc( cyg_int32 /* size */ ); + + // resize existing allocation, if oldsize is non-NULL, previous + // allocation size is placed into it. If previous size not available, + // it is set to 0. NB previous allocation size may have been rounded up. + // Occasionally the allocation can be adjusted *backwards* as well as, + // or instead of forwards, therefore the address of the resized + // allocation is returned, or NULL if no resizing was possible. + // Note that this differs from ::realloc() in that no attempt is + // made to call malloc() if resizing is not possible - that is left + // to higher layers. The data is copied from old to new though. + // The effects of alloc_ptr==NULL or newsize==0 are undefined + cyg_uint8 * + resize_alloc( cyg_uint8 * /* alloc_ptr */, cyg_int32 /* newsize */, + cyg_int32 * /* oldsize */ ); + + // free size bytes of memory back to the pool + // returns true on success + cyg_bool + free( cyg_uint8 * /* ptr */, + cyg_int32 /* size */ ); + + // Get memory pool status + // flags is a bitmask of requested fields to fill in. The flags are + // defined in common.hxx + void + get_status( cyg_mempool_status_flag_t /* flags */, + Cyg_Mempool_Status & /* status */ ); + +}; + +#include + +// ------------------------------------------------------------------------- +#endif // ifndef CYGONCE_MEMALLOC_SEPMETAIMPL_HXX +// EOF sepmetaimpl.hxx diff --git a/packages/services/memalloc/common/current/include/sepmetaimpl.inl b/packages/services/memalloc/common/current/include/sepmetaimpl.inl new file mode 100644 --- /dev/null +++ b/packages/services/memalloc/common/current/include/sepmetaimpl.inl @@ -0,0 +1,657 @@ +#ifndef CYGONCE_MEMALLOC_SEPMETAIMPL_INL +#define CYGONCE_MEMALLOC_SEPMETAIMPL_INL + +//========================================================================== +// +// sepmetaimpl.inl +// +// Variable block memory pool with separate metadata class declarations +// +//========================================================================== +//####COPYRIGHTBEGIN#### +// +// ------------------------------------------- +// The contents of this file are subject to the Red Hat eCos Public License +// Version 1.1 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://www.redhat.com/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations under +// the License. +// +// The Original Code is eCos - Embedded Configurable Operating System, +// released September 30, 1998. +// +// The Initial Developer of the Original Code is Red Hat. +// Portions created by Red Hat are +// Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc. +// All Rights Reserved. +// ------------------------------------------- +// +//####COPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): jlarmour +// Contributors: hmt +// Date: 2001-06-28 +// Purpose: Define Sepmetaimpl class interface +// Description: Inline class for constructing a variable block allocator +// with separate metadata. +// Usage: #include +// +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include +#ifdef CYGPKG_ISOINFRA +# include +#endif +#include +#include + +#include // assertion support +#include // tracing support + +// Simple allocator + +// The memory block lists are doubly linked lists. One for all alloced +// blocks, one for all free blocks. There's also a list of unused +// metadata from the metadata pool. The head of the +// list has the same structure but its memnext/memprev fields are zero. +// Always having at least one item on the list simplifies the alloc and +// free code. +#if CYGINT_ISO_STRING_MEMFUNCS +# include +#endif + +inline void +Cyg_Mempool_Sepmeta_Implementation::copy_data( cyg_uint8 *dst, + cyg_uint8 *src, + cyg_int32 nbytes ) +{ +#if CYGINT_ISO_STRING_MEMFUNCS + memmove( dst, src, nbytes ); +#else + if ((src < dst) && (dst < (src + nbytes))) { + // Have to copy backwards + src += nbytes; + dst += nbytes; + while (nbytes--) { + *--dst = *--src; + } + } else { + while (nbytes--) { + *dst++ = *src++; + } + } +#endif +} + +inline cyg_uint8 * +Cyg_Mempool_Sepmeta_Implementation::alignup( cyg_uint8 *addr ) +{ + return (cyg_uint8 *)((cyg_int32)(addr + alignment-1) & -alignment); +} + +inline cyg_uint8 * +Cyg_Mempool_Sepmeta_Implementation::aligndown( cyg_uint8 *addr ) +{ + return (cyg_uint8 *)((cyg_int32)addr & -alignment); +} + +inline cyg_uint8 * +Cyg_Mempool_Sepmeta_Implementation::alignmetaup( cyg_uint8 *addr ) +{ + const size_t memdqalign = __alignof__ (struct memdq); + return (cyg_uint8 *)((cyg_int32)(addr + memdqalign-1) & -memdqalign); +} + +inline cyg_uint8 * +Cyg_Mempool_Sepmeta_Implementation::alignmetadown( cyg_uint8 *addr ) +{ + const size_t memdqalign = __alignof__ (struct memdq); + return (cyg_uint8 *)((cyg_int32)addr & -memdqalign); +} + +// return the alloced dq at mem +inline struct Cyg_Mempool_Sepmeta_Implementation::memdq * +Cyg_Mempool_Sepmeta_Implementation::find_alloced_dq( cyg_uint8 *mem ) +{ + struct memdq *dq=allocedhead.next; + + while (dq->mem != mem ) { + CYG_ASSERT( dq->next->prev==dq, "Bad link in dq"); + CYG_ASSERT( dq->memnext->memprev==dq, "Bad link in mem dq"); + if (dq->next == &memend) // address not found! + return NULL; + dq = dq->next; + } + return dq; +} + +// returns a free dq of at least size, or NULL if none +inline struct Cyg_Mempool_Sepmeta_Implementation::memdq * +Cyg_Mempool_Sepmeta_Implementation::find_free_dq( cyg_int32 size ) +{ + struct memdq *dq = freehead.next; + + while ( (dq->memnext->mem - dq->mem) < size ) { + CYG_ASSERT( dq->next->prev==dq, "Bad link in dq"); + CYG_ASSERT( dq->memnext->memprev==dq, "Bad link in mem dq"); + if (dq->next == &freehead) { // reached end of list + return NULL; + } + dq = dq->next; // next on free list + } + return dq; +} + +// returns the free dq following mem +inline struct Cyg_Mempool_Sepmeta_Implementation::memdq * +Cyg_Mempool_Sepmeta_Implementation::find_free_dq_slot( cyg_uint8 *mem ) +{ + struct memdq *dq; + for (dq = freehead.next; dq->mem < mem; dq = dq->next) { + if ( dq == &freehead ) // wrapped round + break; + } + return dq; +} + +inline void +Cyg_Mempool_Sepmeta_Implementation::check_free_memdq( struct memdq *dq ) +{ + if (dq == &freehead) + return; + CYG_ASSERT(dq->memnext->memprev == dq, "corrupted free dq #1"); + CYG_ASSERT(dq->next->prev == dq, "corrupted free dq #2"); + CYG_ASSERT(dq->memprev->memnext == dq, "corrupted free dq #3"); + CYG_ASSERT(dq->prev->next == dq, "corrupted free dq #4"); + CYG_ASSERT(dq->memnext->mem > dq->mem, "free dq mem not sorted #1"); + if (dq->memprev != &memend) + CYG_ASSERT(dq->memprev->mem < dq->mem, "free dq mem not sorted #2"); +} + +inline void +Cyg_Mempool_Sepmeta_Implementation::check_alloced_memdq( struct memdq *dq ) +{ + CYG_ASSERT(dq->memnext->memprev == dq, "corrupted alloced dq #1"); + CYG_ASSERT(dq->next->prev == dq, "corrupted alloced dq #2"); + CYG_ASSERT(dq->memprev->memnext == dq, "corrupted alloced dq #3"); + CYG_ASSERT(dq->prev->next == dq, "corrupted alloced dq #4"); + if (dq != &memend) + CYG_ASSERT(dq->memnext->mem > dq->mem, "alloced dq mem not sorted #1"); + if (dq->memprev != &memhead) + CYG_ASSERT(dq->memprev->mem < dq->mem, "alloced dq mem not sorted #2"); +} + +// ------------------------------------------------------------------------- + +inline void +Cyg_Mempool_Sepmeta_Implementation::insert_free_block( struct memdq *dq ) +{ + // scan for correct slot in the sorted free list + struct memdq *fdq = find_free_dq_slot( dq->mem ); + + CYG_ASSERT(fdq != &freehead ? fdq->mem > dq->mem : 1, + "Block address is already in freelist"); + + check_free_memdq(fdq); + + if (dq->memnext == fdq) { + // we can coalesce these two together + // adjust fdq's mem address backwards to include dq + fdq->mem = dq->mem; + // and remove dq + fdq->memprev = dq->memprev; + fdq->memprev->memnext = fdq; + // Don't need to adjust fdq's next/prev links as it stays in the + // same place in the free list + + // dq is now redundant so return to metadata free list + dq->next = freemetahead; + freemetahead = dq; + + // reset dq + dq = fdq; + } else { + // insert behind fdq + dq->next = fdq; + dq->prev = fdq->prev; + fdq->prev = dq; + dq->prev->next = dq; + } + + check_free_memdq(dq); + + // maybe also coalesce backwards + if (dq->memprev == dq->prev) { + // adjust dq's mem address backwards to include dq->prev + dq->mem = dq->prev->mem; + + // return dq->prev to metadata free list + dq->prev->next = freemetahead; + freemetahead = dq->prev; + + // and remove dq->prev from mem list + dq->memprev = dq->prev->memprev; + dq->memprev->memnext = dq; + // and free list + dq->prev = dq->prev->prev; + dq->prev->next = dq; + + check_free_memdq(dq); + } +} + +// ------------------------------------------------------------------------- +#include +inline +Cyg_Mempool_Sepmeta_Implementation::Cyg_Mempool_Sepmeta_Implementation( + cyg_uint8 *base, + cyg_int32 size, + CYG_ADDRWORD consargs) +{ + CYG_REPORT_FUNCTION(); + struct constructorargs *args = (struct constructorargs *)consargs; + CYG_CHECK_DATA_PTRC( args ); + + alignment = args->alignment; + + CYG_ASSERT( alignment > 0, "Bad alignment" ); + CYG_ASSERT( 0!=alignment, "alignment is zero" ); + CYG_ASSERT( 0==(alignment & alignment-1), "alignment not a power of 2" ); + + obase=base; + osize=size; + metabase = args->metabase; + metasize = args->metasize; + + // bottom is set to the lowest available address given the alignment. + bottom = alignup( base ); + cyg_uint8 *metabottom = alignmetaup( metabase ); + + // because we split free blocks by allocating memory from the end, not + // the beginning, then to preserve alignment, the *top* must also be + // aligned + top = aligndown( base+size ); + cyg_uint8 *metatop = metabottom + + sizeof(struct memdq)*(metasize/sizeof(struct memdq)); + + CYG_ASSERT( top > bottom , "heap too small" ); + CYG_ASSERT( top <= (base+size), "top too large" ); + CYG_ASSERT( (((cyg_int32)(top)) & alignment-1)==0, + "top badly aligned" ); + CYG_ASSERT( (((cyg_int32)(bottom)) & alignment-1)==0, + "bottom badly aligned" ); + + CYG_ASSERT( metatop > metabottom , "meta space too small" ); + CYG_ASSERT( metatop <= (metabase+metasize), "metatop too large" ); + + // Initialize list of unused metadata blocks. Only need to do next + // pointers - can ignore prev and size + struct memdq *fq = freemetahead = (struct memdq *)metabottom; + + while ((cyg_uint8 *)fq < metatop) { + fq->next = fq+1; + fq++; + } + + CYG_ASSERT((cyg_uint8 *)fq == metatop, "traversed metadata not aligned"); + + // set final pointer to NULL; + --fq; fq->next = NULL; + + // initialize the free list. memhead is the initial free block occupying + // all of free memory. + memhead.next = memhead.prev = &freehead; + // The mem list is circular for consistency. + memhead.memprev = memhead.memnext = &memend; + memhead.mem = bottom; + + // initialize block that indicates end of memory. This pretends to + // be an allocated block + memend.next = memend.prev = &allocedhead; + memend.memnext = memend.memprev = &memhead; + memend.mem = top; + + // initialize alloced list memdq. memend pretends to be allocated memory + // at the end + allocedhead.next = allocedhead.prev = &memend; + freehead.next = freehead.prev = &memhead; + // Since allocedhead and freehead are placeholders, not real blocks, + // assign addresses which can't match list searches + allocedhead.memnext = allocedhead.memprev = NULL; + freehead.memnext = freehead.memprev = NULL; + freehead.mem = allocedhead.mem = NULL; + + freemem = top - bottom; +} + +// ------------------------------------------------------------------------- + +inline +Cyg_Mempool_Sepmeta_Implementation::~Cyg_Mempool_Sepmeta_Implementation() +{ +} + +// ------------------------------------------------------------------------- +// allocation is mostly simple +// First we look down the free list for a large enough block +// If we find a block the right size, we unlink the block from +// the free list and return a pointer to it. +// If we find a larger block, we chop a piece off the end +// and return that +// Otherwise we reach the end of the list and return NULL + +inline cyg_uint8 * +Cyg_Mempool_Sepmeta_Implementation::try_alloc( cyg_int32 size ) +{ + struct memdq *alloced; + + CYG_REPORT_FUNCTION(); + + // Allow uninitialised (zero sized) heaps because they could exist as a + // quirk of the MLT setup where a dynamically sized heap is at the top of + // memory. + if (NULL == bottom || NULL==metabase) + return NULL; + + size = (size + alignment - 1) & -alignment; + + struct memdq *dq = find_free_dq( size ); + if (NULL == dq) + return NULL; + + cyg_int32 dqsize = dq->memnext->mem - dq->mem; + + if( size == dqsize ) { + // exact fit -- unlink from free list + dq->prev->next = dq->next; + dq->next->prev = dq->prev; + + // set up this block for insertion into alloced list + dq->next = dq->memnext; // since dq was free, dq->memnext must + // be allocated otherwise it would have + // been coalesced + dq->prev = dq->next->prev; + + alloced = dq; + } else { + + CYG_ASSERT( dqsize > size, "block found is too small"); + + // Split into two memdq's, returning the second one + + // first get a memdq + + if ( NULL == freemetahead ) // out of metadata. + return NULL; + + // FIXME: since we don't search all the way for an exact fit + // first we may be able to find an exact fit later and therefore + // not need more metadata. We don't do this yet though. + + alloced = freemetahead; + freemetahead = alloced->next; + + // now set its values + alloced->memnext = dq->memnext; + alloced->next = dq->memnext; // since dq was free, dq->memnext must + // be allocated otherwise it would have + // been coalesced + alloced->memprev = dq; + alloced->prev = alloced->next->prev; + + alloced->mem = alloced->next->mem - size; + + // now set up dq (the portion that remains a free block) + // dq->next and dq->prev are unchanged as we still end up pointing + // at the same adjacent free blocks + // dq->memprev obviously doesn't change + + dq->memnext = alloced; + + // finish inserting into memory block list + alloced->memnext->memprev = alloced; + alloced->next->prev = alloced->prev->next = alloced; + + check_free_memdq(dq); + } + + CYG_ASSERT( bottom <= alloced->mem && alloced->mem <= top, + "alloced outside pool" ); + + // Insert block into alloced list. + alloced->next->prev = alloced->prev->next = alloced; + + check_alloced_memdq(alloced); + + freemem -=size; + + CYG_ASSERT( ((CYG_ADDRESS)alloced->mem & (alignment-1)) == 0, + "returned memory not aligned" ); + return alloced->mem; +} + +// ------------------------------------------------------------------------- +// resize existing allocation, if oldsize is non-NULL, previous +// allocation size is placed into it. If previous size not available, +// it is set to 0. NB previous allocation size may have been rounded up. +// Occasionally the allocation can be adjusted *backwards* as well as, +// or instead of forwards, therefore the address of the resized +// allocation is returned, or NULL if no resizing was possible. +// Note that this differs from ::realloc() in that no attempt is +// made to call malloc() if resizing is not possible - that is left +// to higher layers. The data is copied from old to new though. +// The effects of alloc_ptr==NULL or newsize==0 are undefined + +inline cyg_uint8 * +Cyg_Mempool_Sepmeta_Implementation::resize_alloc( cyg_uint8 *alloc_ptr, + cyg_int32 newsize, + cyg_int32 *oldsize ) +{ + cyg_int32 currsize, origsize; + + CYG_REPORT_FUNCTION(); + + CYG_CHECK_DATA_PTRC( alloc_ptr ); + if ( NULL != oldsize ) + CYG_CHECK_DATA_PTRC( oldsize ); + + CYG_ASSERT( (bottom <= alloc_ptr) && (alloc_ptr <= top), + "alloc_ptr outside pool" ); + + struct memdq *dq=find_alloced_dq( alloc_ptr ); + CYG_ASSERT( dq != NULL, "passed address not previously alloced"); + + currsize = origsize = dq->memnext->mem - dq->mem; + if ( NULL != oldsize ) + *oldsize = currsize; + + if ( newsize > currsize ) { + cyg_int32 nextmemsize=0, prevmemsize=0; + + // see if we can increase the allocation size. Don't change anything + // so we don't have to undo it later if it wouldn't fit + if ( dq->next != dq->memnext ) { // if not equal, memnext must + // be on free list + nextmemsize = dq->memnext->memnext->mem - dq->memnext->mem; + } + if ( dq->prev != dq->memprev) { // ditto + prevmemsize = dq->mem - dq->memprev->mem; + } + if (nextmemsize + prevmemsize + currsize < newsize) + return NULL; // can't fit it + + // expand forwards + if ( nextmemsize != 0 ) { + if (nextmemsize <= (newsize - currsize)) { // taking all of it + struct memdq *fblk = dq->memnext; + + // fix up mem list ptrs + dq->memnext = fblk->memnext; + dq->memnext->memprev=dq; + // fix up free list ptrs + fblk->next->prev = fblk->prev; + fblk->prev->next = fblk->next; + + // return to meta list + fblk->next = freemetahead; + freemetahead = fblk->next; + currsize += nextmemsize; + } else { // only needs some + dq->memnext->mem += (newsize - currsize); + currsize = newsize; + } + } + + // expand backwards + if ( currsize < newsize && prevmemsize != 0 ) { + cyg_uint8 *oldmem = dq->mem; + + CYG_ASSERT( prevmemsize >= newsize - currsize, + "miscalculated expansion" ); + if (prevmemsize == (newsize - currsize)) { // taking all of it + struct memdq *fblk = dq->memprev; + + // fix up mem list ptrs + dq->memprev = fblk->memprev; + dq->memprev->memnext=dq; + dq->mem = fblk->mem; + // fix up free list ptrs + fblk->next->prev = fblk->prev; + fblk->prev->next = fblk->next; + + // return to meta list + fblk->next = freemetahead; + freemetahead = fblk->next; + } else { // only needs some + dq->mem -= (newsize - currsize); + } + + // move data into place + copy_data( dq->mem, oldmem, origsize ); + } + } + + if (newsize < currsize) { + // shrink allocation + + // easy if the next block is already a free block + if ( dq->memnext != dq->next ) { + dq->memnext->mem -= currsize - newsize; + CYG_ASSERT( dq->memnext->mem > dq->mem, + "moving next block back corruption" ); + } else { + // if its already allocated we need to create a new free list + // entry + if (NULL == freemetahead) + return NULL; // can't do it + + struct memdq *fdq = freemetahead; + freemetahead = fdq->next; + + fdq->memprev = dq; + fdq->memnext = dq->memnext; + fdq->mem = dq->mem + newsize; + + insert_free_block( fdq ); + } + } + + freemem += origsize - newsize; + + return dq->mem; +} // resize_alloc() + + +// ------------------------------------------------------------------------- +// When no coalescing is done, free is simply a matter of using the +// freed memory as an element of the free list linking it in at the +// start. When coalescing, the free list is sorted + +inline cyg_bool +Cyg_Mempool_Sepmeta_Implementation::free( cyg_uint8 *p, cyg_int32 size ) +{ + CYG_REPORT_FUNCTION(); + + CYG_CHECK_DATA_PTRC( p ); + + if (!((bottom <= p) && (p <= top))) + return false; + + struct memdq *dq = find_alloced_dq( p ); + if (NULL == dq) + return false; + + if (0 == size) + size = dq->memnext->mem - dq->mem; + else { + size = (size + alignment - 1) & -alignment; + if( (dq->memnext->mem - dq->mem) != size ) + return false; + } + + check_alloced_memdq( dq ); + + // Remove dq from alloced list + dq->prev->next = dq->next; + dq->next->prev = dq->prev; + + insert_free_block( dq ); + + freemem += size; + + return true; +} + +// ------------------------------------------------------------------------- + +inline void +Cyg_Mempool_Sepmeta_Implementation::get_status( + cyg_mempool_status_flag_t flags, + Cyg_Mempool_Status &status ) +{ + CYG_REPORT_FUNCTION(); + +// as quick or quicker to just set it, rather than test flag first + status.arenabase = obase; + if ( 0 != (flags & CYG_MEMPOOL_STAT_ARENASIZE) ) + status.arenasize = top - bottom; + if ( 0 != (flags & CYG_MEMPOOL_STAT_TOTALALLOCATED) ) + status.totalallocated = (top-bottom) - freemem; +// as quick or quicker to just set it, rather than test flag first + status.totalfree = freemem; + if ( 0 != (flags & CYG_MEMPOOL_STAT_MAXFREE) ) { + struct memdq *dq = &freehead; + cyg_int32 mf = 0; + + do { + CYG_ASSERT( dq->next->prev==dq, "Bad link in dq"); + dq = dq->next; + if (dq == &freehead) // wrapped round + break; + if(dq->memnext->mem - dq->mem > mf) + mf = dq->memnext->mem - dq->mem; + } while(1); + status.maxfree = mf; + } +// as quick or quicker to just set it, rather than test flag first + status.origbase = obase; +// as quick or quicker to just set it, rather than test flag first + status.origsize = osize; + + CYG_REPORT_RETURN(); + +} // get_status() + + +// ------------------------------------------------------------------------- +#endif // ifndef CYGONCE_MEMALLOC_SEPMETAIMPL_INL +// EOF sepmetaimpl.inl diff --git a/packages/services/memalloc/common/current/src/malloc.cxx b/packages/services/memalloc/common/current/src/malloc.cxx --- a/packages/services/memalloc/common/current/src/malloc.cxx +++ b/packages/services/memalloc/common/current/src/malloc.cxx @@ -58,7 +58,11 @@ #include // Common assertion support #include // For memset() and memmove() #include // header for this file -#include // heap pools information +#ifdef CYGBLD_MEMALLOC_MALLOC_EXTERNAL_HEAP_H +# include CYGBLD_MEMALLOC_MALLOC_EXTERNAL_HEAP_H +#else +# include // heap pools information +#endif #include CYGBLD_MEMALLOC_MALLOC_IMPLEMENTATION_HEADER // STATIC VARIABLES diff --git a/packages/services/memalloc/common/current/src/sepmeta.cxx b/packages/services/memalloc/common/current/src/sepmeta.cxx new file mode 100644 --- /dev/null +++ b/packages/services/memalloc/common/current/src/sepmeta.cxx @@ -0,0 +1,175 @@ +//========================================================================== +// +// sepmeta.cxx +// +// Variable block memory pool with separated metadata class declarations +// +//========================================================================== +//####COPYRIGHTBEGIN#### +// +// ------------------------------------------- +// The contents of this file are subject to the Red Hat eCos Public License +// Version 1.1 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://www.redhat.com/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations under +// the License. +// +// The Original Code is eCos - Embedded Configurable Operating System, +// released September 30, 1998. +// +// The Initial Developer of the Original Code is Red Hat. +// Portions created by Red Hat are +// Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc. +// All Rights Reserved. +// ------------------------------------------- +// +//####COPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): jlarmour +// Contributors: +// Date: 2001-06-28 +// Description: +// Usage: #include +// +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +// CONFIGURATION + +#include +#include +#ifdef CYGPKG_KERNEL +# include +#endif + + +// INCLUDES + +#include // types +#include // assertion macros +#include // tracing macros + +#ifdef CYGFUN_KERNEL_THREADS_TIMER +# include // cyg_tick_count +#endif + +#ifdef CYGSEM_MEMALLOC_ALLOCATOR_SEPMETA_THREADAWARE +# include // kernel safe mempool template +#endif + +#include +#include // implementation of this mem pool +#include // Common memory allocator infra + +// FUNCTIONS + +// ------------------------------------------------------------------------- +// debugging/assert function + +#ifdef CYGDBG_USE_ASSERTS +cyg_bool +Cyg_Mempool_Sepmeta::check_this(cyg_assert_class_zeal zeal) const +{ + CYG_REPORT_FUNCTION(); + // check that we have a non-NULL pointer first + if( this == NULL ) return false; +#ifdef CYGSEM_MEMALLOC_ALLOCATOR_SEPMETA_THREADAWARE + return mypool.check_this( zeal ); +#else + return true; +#endif +} +#endif + +// ------------------------------------------------------------------------- +// Constructor: gives the base and size of the arena in which memory is +// to be carved out +Cyg_Mempool_Sepmeta::Cyg_Mempool_Sepmeta( + cyg_uint8 *base, + cyg_int32 size, + cyg_int32 alignment, + cyg_uint8 *metabase, + cyg_uint32 metasize) + : args(alignment, metabase, metasize), + mypool( base, size, (CYG_ADDRWORD)&args ) +{ +} + +// Destructor +Cyg_Mempool_Sepmeta::~Cyg_Mempool_Sepmeta() +{ +} + +// ------------------------------------------------------------------------- +// get some memory; wait if none available +#ifdef CYGSEM_MEMALLOC_ALLOCATOR_SEPMETA_THREADAWARE +cyg_uint8 * +Cyg_Mempool_Sepmeta::alloc(cyg_int32 size) +{ + return mypool.alloc( size ); +} + +# ifdef CYGFUN_KERNEL_THREADS_TIMER +// get some memory with a timeout +cyg_uint8 * +Cyg_Mempool_Sepmeta::alloc(cyg_int32 size, cyg_tick_count delay_timeout) +{ + return mypool.alloc( size , delay_timeout ); +} +# endif +#endif + +// get some memory, return NULL if none available +cyg_uint8 * +Cyg_Mempool_Sepmeta::try_alloc(cyg_int32 size) +{ + return mypool.try_alloc( size ); +} + +// resize existing allocation, if oldsize is non-NULL, previous +// allocation size is placed into it. If previous size not available, +// it is set to 0. NB previous allocation size may have been rounded up. +// Occasionally the allocation can be adjusted *backwards* as well as, +// or instead of forwards, therefore the address of the resized +// allocation is returned, or NULL if no resizing was possible. +// Note that this differs from ::realloc() in that no attempt is +// made to call malloc() if resizing is not possible - that is left +// to higher layers. The data is copied from old to new though. +// The effects of alloc_ptr==NULL or newsize==0 are undefined +cyg_uint8 * +Cyg_Mempool_Sepmeta::resize_alloc( cyg_uint8 *alloc_ptr, cyg_int32 newsize, + cyg_int32 *oldsize ) +{ + return mypool.resize_alloc( alloc_ptr, newsize, oldsize ); +} + +// free the memory back to the pool +cyg_bool +Cyg_Mempool_Sepmeta::free( cyg_uint8 *p, cyg_int32 size ) +{ + return mypool.free( p, size ); +} + +// Get memory pool status +void +Cyg_Mempool_Sepmeta::get_status( cyg_mempool_status_flag_t flags, + Cyg_Mempool_Status &status ) +{ + // set to 0 - if there's anything really waiting, it will be set to + // 1 later + status.waiting = 0; + + return mypool.get_status( flags, status ); +} + +// ------------------------------------------------------------------------- + +// End of sepmeta.cxx diff --git a/packages/services/memalloc/common/current/tests/sepmeta1.cxx b/packages/services/memalloc/common/current/tests/sepmeta1.cxx new file mode 100644 --- /dev/null +++ b/packages/services/memalloc/common/current/tests/sepmeta1.cxx @@ -0,0 +1,216 @@ +//========================================================================== +// +// sepmeta1.cxx +// +// Variable memory pool with separate metadata test 1 +// +//========================================================================== +//####COPYRIGHTBEGIN#### +// +// ------------------------------------------- +// The contents of this file are subject to the Red Hat eCos Public License +// Version 1.1 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://www.redhat.com/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations under +// the License. +// +// The Original Code is eCos - Embedded Configurable Operating System, +// released September 30, 1998. +// +// The Initial Developer of the Original Code is Red Hat. +// Portions created by Red Hat are +// Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc. +// All Rights Reserved. +// ------------------------------------------- +// +//####COPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): dsm, jlarmour +// Contributors: +// Date: 2001-06-28 +// Description: Tests basic variable memory pool functionality +//####DESCRIPTIONEND#### + +#include +#include + +#ifdef CYGPKG_KERNEL +#include + +#include // Cyg_Scheduler::start() +#include // Cyg_Thread + +#include +#include + +#include // Cyg_Timer +#include // Cyg_Clock + +#define NTHREADS 2 +#include "testaux.hxx" + +#endif + +#include + +#include + +static const cyg_int32 memsize = 10240; +static const cyg_int32 metadatasize = 2048; + +static cyg_uint8 mem[2][memsize]; +static cyg_uint8 metadata[2][metadatasize]; + +static Cyg_Mempool_Sepmeta mempool0(mem[0], memsize, 8, + metadata[0], metadatasize); + +static Cyg_Mempool_Sepmeta mempool1(mem[1], memsize, 8, + metadata[1], metadatasize); + + +static void check_in_mp0(cyg_uint8 *p, cyg_int32 size) +{ + CYG_TEST_CHECK(NULL != p, + "Allocation failed"); + CYG_TEST_CHECK(mem[0] <= p && p+size <= mem[1], + "Block outside memory pool"); +} + + +static void entry0( CYG_ADDRWORD data ) +{ + cyg_int32 f0,f1,f2,t0; + cyg_uint8 *p0, *p1; + cyg_int32 most_of_mem=memsize/4*3; + Cyg_Mempool_Status stat; + + mempool0.get_status( CYG_MEMPOOL_STAT_ORIGBASE| + CYG_MEMPOOL_STAT_BLOCKSIZE| + CYG_MEMPOOL_STAT_MAXFREE| + CYG_MEMPOOL_STAT_ORIGSIZE, stat ); + + CYG_TEST_CHECK(mem[0] == stat.origbase, "get_status: base wrong"); + CYG_TEST_CHECK(memsize == stat.origsize, "get_status: size wrong"); + + CYG_TEST_CHECK(0 < stat.maxfree && stat.maxfree <= stat.origsize, + "get_status: maxfree wildly wrong"); + + CYG_TEST_CHECK(-1 == stat.blocksize, "blocksize wrong" ); + + mempool0.get_status( CYG_MEMPOOL_STAT_TOTALFREE| + CYG_MEMPOOL_STAT_ARENASIZE, stat ); + t0 = stat.arenasize; + CYG_TEST_CHECK(t0 > 0, "Negative total memory" ); + f0 = stat.totalfree; + CYG_TEST_CHECK(f0 > 0, "Negative free memory" ); + CYG_TEST_CHECK(t0 <= memsize, "get_totalsize: Too much memory"); + CYG_TEST_CHECK(f0 <= t0 , "More memory free than possible" ); + + mempool0.get_status( CYG_MEMPOOL_STAT_WAITING, stat ); + CYG_TEST_CHECK( !stat.waiting, + "Thread waiting for memory; there shouldn't be"); + + CYG_TEST_CHECK( NULL == mempool0.try_alloc(memsize+1), + "Managed to allocate too much memory"); + +#ifdef CYGSEM_MEMALLOC_ALLOCATOR_SEPMETA_THREADAWARE + p0 = mempool0.alloc(most_of_mem); +#else + p0 = mempool0.try_alloc(most_of_mem); +#endif + check_in_mp0(p0, most_of_mem); + + mempool0.get_status( CYG_MEMPOOL_STAT_TOTALFREE, stat ); + f1 = stat.totalfree; + CYG_TEST_CHECK(f1 > 0, "Negative free memory" ); + CYG_TEST_CHECK(f1 < f0, "Free memory didn't decrease after allocation" ); + + CYG_TEST_CHECK( NULL == mempool0.try_alloc(most_of_mem), + "Managed to allocate too much memory"); + + CYG_TEST_CHECK(mempool0.free(p0, most_of_mem), "Couldn't free"); + + mempool0.get_status( CYG_MEMPOOL_STAT_TOTALFREE, stat ); + f2 = stat.totalfree; + CYG_TEST_CHECK(f2 > f1, "Free memory didn't increase after free" ); + + // should be able to reallocate now memory is free + p0 = mempool0.try_alloc(most_of_mem); + check_in_mp0(p0, most_of_mem); + + p1 = mempool0.try_alloc(10); + check_in_mp0(p1, 10); + + CYG_TEST_CHECK(p1+10 <= p0 || p1 >= p0+most_of_mem, + "Ranges of allocated memory overlap"); + + CYG_TEST_CHECK(mempool0.free(p0, 0), "Couldn't free"); + CYG_TEST_CHECK(mempool0.free(p1, 10), "Couldn't free"); + +#ifdef CYGSEM_MEMALLOC_ALLOCATOR_SEPMETA_THREADAWARE +# ifdef CYGFUN_KERNEL_THREADS_TIMER + // This shouldn't have to wait + p0 = mempool0.alloc(most_of_mem, + Cyg_Clock::real_time_clock->current_value() + 100000); + check_in_mp0(p0, most_of_mem); + p1 = mempool0.alloc(most_of_mem, + Cyg_Clock::real_time_clock->current_value() + 2); + CYG_TEST_CHECK(NULL == p1, "Timed alloc unexpectedly worked"); + p1 = mempool0.alloc(10, + Cyg_Clock::real_time_clock->current_value() + 2); + check_in_mp0(p1, 10); + + // Expect thread 1 to have run while processing previous timed + // allocation. It should therefore tbe waiting. + mempool1.get_status( CYG_MEMPOOL_STAT_WAITING, stat ); + CYG_TEST_CHECK(stat.waiting, "There should be a thread waiting"); +# endif +#endif + + CYG_TEST_PASS_FINISH("Sepmeta memory pool 1 OK"); +} + +#ifdef CYGSEM_MEMALLOC_ALLOCATOR_SEPMETA_THREADAWARE +static void entry1( CYG_ADDRWORD data ) +{ + mempool1.alloc(memsize+1); + CYG_TEST_FAIL("Oversized alloc returned"); +} +#endif + +void sepmeta1_main( void ) +{ + CYG_TEST_INIT(); + CYG_TEST_INFO("Starting Seperate metadata pool 1 test"); + +#ifdef CYGSEM_MEMALLOC_ALLOCATOR_SEPMETA_THREADAWARE + new_thread(entry0, 0); + new_thread(entry1, 1); + + Cyg_Scheduler::start(); +#elif defined(CYGPKG_KERNEL) + new_thread(entry0, 0); + + Cyg_Scheduler::start(); +#else + entry0(0); +#endif + + CYG_TEST_FAIL_FINISH("Not reached"); +} + +externC void +cyg_start( void ) +{ +#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG + cyg_hal_invoke_constructors(); +#endif + sepmeta1_main(); +} +// EOF sepmeta1.cxx diff --git a/packages/services/memalloc/common/current/tests/sepmeta2.cxx b/packages/services/memalloc/common/current/tests/sepmeta2.cxx new file mode 100644 --- /dev/null +++ b/packages/services/memalloc/common/current/tests/sepmeta2.cxx @@ -0,0 +1,153 @@ +//========================================================================== +// +// sepmeta2.cxx +// +// Variable memory pool with separate metadata test 2 +// +//========================================================================== +//####COPYRIGHTBEGIN#### +// +// ------------------------------------------- +// The contents of this file are subject to the Red Hat eCos Public License +// Version 1.1 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://www.redhat.com/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations under +// the License. +// +// The Original Code is eCos - Embedded Configurable Operating System, +// released September 30, 1998. +// +// The Initial Developer of the Original Code is Red Hat. +// Portions created by Red Hat are +// Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc. +// All Rights Reserved. +// ------------------------------------------- +// +//####COPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): dsm, jlarmour +// Contributors: +// Date: 2001-06-28 +// Description: test allocation and freeing in variable memory pools +//####DESCRIPTIONEND#### + +#include +#include + +#ifdef CYGPKG_KERNEL +#include + +#include // Cyg_Scheduler::start() +#include // Cyg_Thread +#include +#include + +#include + +#define NTHREADS 1 +#include "testaux.hxx" + +#endif + +#include + +#include + +static const cyg_int32 memsize = 10240; +static const cyg_int32 metadatasize = 2048; + +static cyg_uint8 mem[memsize]; +static cyg_uint8 metadata[metadatasize]; + +static Cyg_Mempool_Sepmeta mempool(mem, memsize, 8, + metadata, metadatasize); + +#define NUM_PTRS 16 // Should be even + +static cyg_uint8 *ptr[NUM_PTRS]; +static cyg_int32 size[NUM_PTRS]; + +// We make a number of passes over a table of pointers which point to +// blocks of allocated memory. The block is freed and a new block +// allocated. The size and the order of the processing of blocks +// is varied. +static void entry( CYG_ADDRWORD data ) +{ + cyg_uint32 s = 1; + + // The number of passes that can be successfully performed + // depends on the fragmentation performance of the memory + // allocator. + for(cyg_ucount32 passes = 0; passes < 10; passes++) { + + + // The order which the table is processed varies according to + // stepsize. + cyg_ucount8 stepsize = (passes*2 + 1) % NUM_PTRS; // odd + + + for(cyg_ucount8 c=0, i=0; c < NUM_PTRS; c++) { + i = (i+stepsize) % NUM_PTRS; + if(ptr[i]) { + for(cyg_ucount32 j=size[i];j--;) { + CYG_TEST_CHECK(ptr[i][j]==i, "Memory corrupted"); + } + CYG_TEST_CHECK(mempool.free(ptr[i], size[i]), + "bad free"); + } + s = (s*2 + 17) % 100; // size always odds therefore non-0 + ptr[i] = mempool.try_alloc(s); + size[i] = s; + + CYG_TEST_CHECK(NULL != ptr[i], "Memory pool not big enough"); + CYG_TEST_CHECK(mem<=ptr[i] && ptr[i]+s < mem+memsize, + "Allocated region not within pool"); + + // Scribble over memory to check whether region overlaps + // with other regions. The contents of the memory are + // checked on freeing. This also tests that the memory + // does not overlap with allocator memory structures. + for(cyg_ucount32 j=size[i];j--;) { + ptr[i][j]=i; + } + } + } + + CYG_TEST_PASS_FINISH("Sepmeta memory pool 2 OK"); +} + + +void sepmeta2_main( void ) +{ + CYG_TEST_INIT(); + CYG_TEST_INFO("Starting Seperate metadata memory pool 2 test"); + + for(cyg_ucount32 i = 0; i