[riot-devel] About function pointers
Dear remodeling IoTlers! Ludwig just made me aware that Joakim's PR for NVRAM [1] introduces function pointers as part of the device driver struct. This made me remember that there were already similar function pointers introduced as part of netdev. As I was always opposed to use function pointers in that way, I could not recall what was the reason to use them for netdev. I don't like this pseudo object oriented C style (dev-write() and the like) because we made bad experiences with it at my former company. While writing the whole HAL for our firmware there using function pointers this way, made programming pretty convenient, it turned out to become problematic speed-wise and was a nightmare to debug. Hence, I would like to trigger a fundamental discussion on this topic. Does anyone has a particular opinion on the topic why function pointer based device drivers should be a good or a bad idea? And can anyone explain to me the need of function pointers for netdev? Cheers, Oleg [1] https://github.com/RIOT-OS/RIOT/pull/2353 -- if (user_specified) /* Didn't work, but the user is convinced this is the * place. */ linux-2.4.0-test2/drivers/parport/parport_pc.c pgpRbu6a4LGIk.pgp Description: PGP signature ___ devel mailing list devel@riot-os.org http://lists.riot-os.org/mailman/listinfo/devel
Re: [riot-devel] redbee-econotag board
Hi Ralph, a short update: I spent most of today’s afternoon to set up toolchain and additional tools again which didn’t left much time for testing. I can confirm the latter problem the app yielding. I will continue investigation tomorrow. The first issue I couldn’t reproduce though. I will keep you updated on my findings. Best, Thomas On 18 Feb 2015, at 14:54, Ralph Droms (rdroms) rdr...@cisco.com wrote: On Feb 18, 2015, at 4:18 AM 2/18/15, Thomas Eichinger thomas.eichin...@fu-berlin.de wrote: Hi Ralph, first of all also welcome from my side. Regarding the RIOT support for the redbee-econotag I can remember similar problems which resulted from the compiler used. For this board it is important to note that only the CodeSourcery GCC 2008q3 is supported. Could you check for this? $ arm-none-eabi-gcc -v Using built-in specs. Target: arm-none-eabi Configured with: /scratch/julian/lite-respin/eabi/src/gcc-4.3/configure --build=i686-pc-linux-gnu --host=i686-pc-linux-gnu --target=arm-none-eabi --enable-threads --disable-libmudflap --disable-libssp --disable-libstdcxx-pch --with-gnu-as --with-gnu-ld --enable-languages=c,c++ --disable-shared --with-newlib --with-pkgversion='Sourcery G++ Lite 2008q3-66' --with-bugurl=https://support.codesourcery.com/GNUToolchain/ --disable-nls --prefix=/opt/codesourcery --with-headers=yes --with-sysroot=/opt/codesourcery/arm-none-eabi --with-build-sysroot=/scratch/julian/lite-respin/eabi/install/arm-none-eabi --with-gmp=/scratch/julian/lite-respin/eabi/obj/host-libs-2008q3-66-arm-none-eabi-i686-pc-linux-gnu/usr --with-mpfr=/scratch/julian/lite-respin/eabi/obj/host-libs-2008q3-66-arm-none-eabi-i686-pc-linux-gnu/usr --disable-libgomp --enable-poison-system-directories --with-build-time-tools=/scratch/julian/lite-respin/eabi/install/arm-none-eabi/bin --with-build-time-tools=/scratch/julian/lite-respin/ eabi/install/arm-none-eabi/bin Thread model: single gcc version 4.3.2 (Sourcery G++ Lite 2008q3-66) Regarding the conditional assembly problem - this code snippet doesn't seem to correctly recognize (CPU != mc1322x) (where CPU = mc1322x is set in boards/redbee-econotag/Makefile.include): .if (CPU != mc1322x) /* jump into vic interrupt */ movr0, #0xff00/* lpc23xx */ ldrr0, [r0] addlr,pc,#4 .else /* mc1322x seems to lack a VIC, distinction of IRQ has to be done in SW */ ldrr0, =isr /* mc1322x */ .endif Running the code as distributed yields: Board initialized. kernel_init(): This is RIOT! (Version: 2014.12-415-g1e6e-instant-contiki) kernel_init(): jumping into first task... #!undef abort at 0x1c00a0 (0x6809490E) originating from 0x400fe8 If I force assembly of the .else code, the code doesn't abort but only yields: Board initialized. kernel_init(): This is RIOT! (Version: 2014.12-415-g1e6e-instant-contiki) kernel_init(): jumping into first task... - Ralph I will have a more in depth look on your reported problem in the afternoon. Kind regards, Thomas On 17 Feb 2015, at 22:41, Ralph Droms (rdroms) rdr...@cisco.com wrote: Is redbee-econotag board code still in active development or use? I'm new to RIOT ... tried compiling the default example for redbee-econotag and found an error (maybe more correctly a construct that doesn't work as expected) in the conditional assembly in common.s I put in a patch but now all I get from default is: .CONNECT Size: 69440 bytes Sending /home/rdroms/RIOT/examples/default/bin/redbee-econotag/default.hex done sending files. Board initialized. kernel_init(): This is RIOT! (Version: 2014.12-415-g1e6e-instant-contiki) kernel_init(): jumping into first task... Should default work? - Ralph ___ devel mailing list devel@riot-os.org http://lists.riot-os.org/mailman/listinfo/devel ___ devel mailing list devel@riot-os.org http://lists.riot-os.org/mailman/listinfo/devel ___ devel mailing list devel@riot-os.org http://lists.riot-os.org/mailman/listinfo/devel ___ devel mailing list devel@riot-os.org http://lists.riot-os.org/mailman/listinfo/devel
Re: [riot-devel] About function pointers
Hi All, We use this approach exhaustively (for drivers and practically everything else) with the same result. The struct does not even need to be declared as a const struct if it is used in a way that implies such, though it is definitely more elegant to declare it so. Though I do have a preference for binding prerequisite functions as a part of the interface, rather than hiding them in the body of the code with macros. As a disclaimer, I haven't actually checked the result of this particular style of binding, which in our application does use a dereference to access the function pointer. I will have a shot at that later on. Our decision was that effective modularity was more critical than performance for our driver elements (at least until we experience a performance issue). ie. ` //Initialise the radio device extern int8_t SI446x_init(struct si446x_s *device, transfer_data_function spi_transfer_function, set_pin_function set_sdn, get_pin_function get_cts, get_pin_function get_irq, get_pin_function get_cca); ` Where for the purposes of this example the above are defined so: ` typedef int8_t (*transfer_data_function)(void* context, uint8_t *data, uint8_t size); typedef int8_t (*set_pin_function)(void* context, uint8_t value); typedef int8_t (*get_pin_function)(void* context); ` This means that any dependencies are explicitly defined in the interface, rather than hidden in the source code. It also means that instantiating multiple devices and linking them to different underlying communication channels becomes possible, and you can do some quite neat testing based on that. In my opinion this is a cleaner abstraction, and leads to clearer parallel composition (or wiring) of modules, rather than the oft used vertical composition. I had a bit of a wild rant about this recently, and there is a /very/ draft set of slides if anyone is interested. Hope some of this is valuable, Ryan On 19 February 2015 at 05:28, ROUSSEL Kévin kevin.rous...@inria.fr wrote: Hello, I began to use function pointers in the 'radio_driver.h' when trying to create a unified model for radio drivers. I guess it went over later to the whole netdev effort. My idea then was to have a fast, predictable call chain from the MAC layer to the physical radio transceiver functions: most MAC protocols expect to run with precise delays, and a mechanism relying on message between threads (like 'transceiver') did not fit that need. The model of driver as structs containing function pointers is the one used in Contiki: it seemed quite a natural way to handle the problem to me... In their code, the needed drivers are aliased as 'NETSTACK_xxx' macros, then functions are called by invoking 'NETSTACK_xxx.func()'. I've never seen advanced dereferencing (-) nor object-oriented like constructs in that context. As P. Nikander said, since you are supposed to know your hardware at compile time, these pointers are actually constants that should be resolved at compile (linking) time -- even with GCC. Theoretically, it should be translated by standard indirect calls at the assembler level. Could you tell us more about your previous experiments? It seems quite strange to me that such a mechanism (that seems simple to me) could impose speed and debugging penalties. The other question is how could we implement the network stack? Using a mechanism like 'transceiver', that relies on message-passing between threads, implies that there is no predictable delay for executing network functions (one has to wait for the scheduler to switch to the thread(s) that execute(s) the feature(s) you want to use). At some levels -- like between MAC and PHY -- this can be a huge disadvantage. Is there a better way to obtain deterministic/direct API calls than using the struct of function pointers scheme ?... Regards, Le 18/02/2015 11:38, Oleg Hahm a écrit : Dear remodeling IoTlers! Ludwig just made me aware that Joakim's PR for NVRAM [1] introduces function pointers as part of the device driver struct. This made me remember that there were already similar function pointers introduced as part of netdev. As I was always opposed to use function pointers in that way, I could not recall what was the reason to use them for netdev. I don't like this pseudo object oriented C style (dev-write() and the like) because we made bad experiences with it at my former company. While writing the whole HAL for our firmware there using function pointers this way, made programming pretty convenient, it turned out to become problematic speed-wise and was a nightmare to debug. Hence, I would like to trigger a fundamental discussion on this topic. Does anyone has a particular opinion on the topic why function pointer based device drivers should be a good or a bad idea? And can anyone explain to me the need of
Re: [riot-devel] About function pointers
Hi Pekka, thanks for your input. Of course, some care is needed to make sure that the compiler does the right thing. It is relatively easy to break the pattern. I see your point, but actually, I don't want to build a whole system model based on any assumption about what the compiler might optimize. Without testing I'm pretty sure that you're right and an up-to-date version of GCC is able to optimize static function pointers, but we don't know which weird compilers on some esoteric hardware platform might be used for RIOT somewhere sometime, so I rather rely on optimized C code than on optimized compilers. Cheers, Oleg -- The four hard things in CS are cache invalidation, naming, and off-by-one errors. pgpuXrBOHbMyR.pgp Description: PGP signature ___ devel mailing list devel@riot-os.org http://lists.riot-os.org/mailman/listinfo/devel
Re: [riot-devel] About function pointers
Hi Kévin! I began to use function pointers in the 'radio_driver.h' when trying to create a unified model for radio drivers. I guess it went over later to the whole netdev effort. Yes, I remember that, but why can't this be implemented in a similar way we did for most of the peripheral drivers like SPI? Instead of calling a function pointer, we simply pass a struct describing the low-level device (driver) that should be used. My idea then was to have a fast, predictable call chain from the MAC layer to the physical radio transceiver functions: most MAC protocols expect to run with precise delays, and a mechanism relying on message between threads (like 'transceiver') did not fit that need. I completely agree on the point that we need to have direct function calls for MAC protocols (see also http://arxiv.org/abs/1502.01968). The model of driver as structs containing function pointers is the one used in Contiki: it seemed quite a natural way to handle the problem to me... In their code, the needed drivers are aliased as 'NETSTACK_xxx' macros, then functions are called by invoking 'NETSTACK_xxx.func()'. I think it is indeed one of the two natural solutions - the other one would be MACROing everything. I made experiences with both versions while developing on firmware for older sensor board platforms. And both had their drawbacks. Thus, when I started to work on what now is known as RIOT, I wanted to avoid Macros and a function pointer based abstraction layer model as much as possible. Of course, there are cases where either the one or the other will be the best solution, but I think we have to make sure to check if there are no alternative solutions that might work better on the long run. As P. Nikander said, since you are supposed to know your hardware at compile time, these pointers are actually constants that should be resolved at compile (linking) time -- even with GCC. Theoretically, it should be translated by standard indirect calls at the assembler level. You name it: If everything is known at link time, then there is also always a way around function pointers. As I've written in the previous mail: I'd rather tell the compiler (or linker) how to do the stuff in an efficient way than hoping for the toolchain being smarter than me. Could you tell us more about your previous experiments? It seems quite strange to me that such a mechanism (that seems simple to me) could impose speed and debugging penalties. I cannot disclose any code here, because it was proprietary code for my old company, but the problem was a layered one. We had a highly abstracted driver model, similar to Linux' one with char and block devices, abstracted serial line devices and the like. Thus, an application or any high level code accessing low-level drivers would be de-referenced multiple times. This made it incredible hard to debug (because you had to follow all the pointer de-referencing) and made it almost impossible to hold some strict deadlines for TDMA on our old MSP430F1612. The other question is how could we implement the network stack? Using a mechanism like 'transceiver', that relies on message-passing between threads, implies that there is no predictable delay for executing network functions (one has to wait for the scheduler to switch to the thread(s) that execute(s) the feature(s) you want to use). At some levels -- like between MAC and PHY -- this can be a huge disadvantage. I think we can live with the overhead of IPC calls on all layers except the MAC protocol. However, even message-passing has a predictable delay in RIOT - just the concrete numbers might be to high for some low latency MAC protocols. But again, I'm definitely not arguing against function calls for these tasks, just wondering if function pointers are the smartest solution here. (And I'm not saying that they're not...) Cheers, Oleg -- printk(CPU[%d]: Giving pardon to imprisoned penguins\n, smp_processor_id()); linux-2.4.8/arch/sparc64/kernel/smp.c pgpRheajnL991.pgp Description: PGP signature ___ devel mailing list devel@riot-os.org http://lists.riot-os.org/mailman/listinfo/devel
Re: [riot-devel] About function pointers
Hi Ryan! In my opinion this is a cleaner abstraction, and leads to clearer parallel composition (or wiring) of modules, rather than the oft used vertical composition. So, basically you're saying that trading some performance for a cleaner design is a good thing, is that right? I would say that this is very aligned with RIOT's usual design goals and therefore I agree. The question is: how much performance can we give away for this before we hit the limits? Remember, we don't have to care only for rather powerful ARM MCUs, but also for their little 8 and 16 bit brothers and sisters running with only a couple of MHz CPU speed. I had a bit of a wild rant about this recently, and there is a /very/ draft set of slides if anyone is interested. I would be interested. Cheers, Oleg -- The bad thing about Kerberos jokes is that I can't tell them to you because I don't trust you and I don't know your name! pgpN0cHAjyxLj.pgp Description: PGP signature ___ devel mailing list devel@riot-os.org http://lists.riot-os.org/mailman/listinfo/devel
Re: [riot-devel] redbee-econotag board
On Feb 18, 2015, at 4:18 AM 2/18/15, Thomas Eichinger thomas.eichin...@fu-berlin.de wrote: Hi Ralph, first of all also welcome from my side. Regarding the RIOT support for the redbee-econotag I can remember similar problems which resulted from the compiler used. For this board it is important to note that only the CodeSourcery GCC 2008q3 is supported. Could you check for this? $ arm-none-eabi-gcc -v Using built-in specs. Target: arm-none-eabi Configured with: /scratch/julian/lite-respin/eabi/src/gcc-4.3/configure --build=i686-pc-linux-gnu --host=i686-pc-linux-gnu --target=arm-none-eabi --enable-threads --disable-libmudflap --disable-libssp --disable-libstdcxx-pch --with-gnu-as --with-gnu-ld --enable-languages=c,c++ --disable-shared --with-newlib --with-pkgversion='Sourcery G++ Lite 2008q3-66' --with-bugurl=https://support.codesourcery.com/GNUToolchain/ --disable-nls --prefix=/opt/codesourcery --with-headers=yes --with-sysroot=/opt/codesourcery/arm-none-eabi --with-build-sysroot=/scratch/julian/lite-respin/eabi/install/arm-none-eabi --with-gmp=/scratch/julian/lite-respin/eabi/obj/host-libs-2008q3-66-arm-none-eabi-i686-pc-linux-gnu/usr --with-mpfr=/scratch/julian/lite-respin/eabi/obj/host-libs-2008q3-66-arm-none-eabi-i686-pc-linux-gnu/usr --disable-libgomp --enable-poison-system-directories --with-build-time-tools=/scratch/julian/lite-respin/eabi/install/arm-none-eabi/bin --with-build-time-tools=/scratch/julian/lite-respin/ eabi/install/arm-none-eabi/bin Thread model: single gcc version 4.3.2 (Sourcery G++ Lite 2008q3-66) Regarding the conditional assembly problem - this code snippet doesn't seem to correctly recognize (CPU != mc1322x) (where CPU = mc1322x is set in boards/redbee-econotag/Makefile.include): .if (CPU != mc1322x) /* jump into vic interrupt */ movr0, #0xff00/* lpc23xx */ ldrr0, [r0] addlr,pc,#4 .else /* mc1322x seems to lack a VIC, distinction of IRQ has to be done in SW */ ldrr0, =isr /* mc1322x */ .endif Running the code as distributed yields: Board initialized. kernel_init(): This is RIOT! (Version: 2014.12-415-g1e6e-instant-contiki) kernel_init(): jumping into first task... #!undef abort at 0x1c00a0 (0x6809490E) originating from 0x400fe8 If I force assembly of the .else code, the code doesn't abort but only yields: Board initialized. kernel_init(): This is RIOT! (Version: 2014.12-415-g1e6e-instant-contiki) kernel_init(): jumping into first task... - Ralph I will have a more in depth look on your reported problem in the afternoon. Kind regards, Thomas On 17 Feb 2015, at 22:41, Ralph Droms (rdroms) rdr...@cisco.com wrote: Is redbee-econotag board code still in active development or use? I'm new to RIOT ... tried compiling the default example for redbee-econotag and found an error (maybe more correctly a construct that doesn't work as expected) in the conditional assembly in common.s I put in a patch but now all I get from default is: .CONNECT Size: 69440 bytes Sending /home/rdroms/RIOT/examples/default/bin/redbee-econotag/default.hex done sending files. Board initialized. kernel_init(): This is RIOT! (Version: 2014.12-415-g1e6e-instant-contiki) kernel_init(): jumping into first task... Should default work? - Ralph ___ devel mailing list devel@riot-os.org http://lists.riot-os.org/mailman/listinfo/devel ___ devel mailing list devel@riot-os.org http://lists.riot-os.org/mailman/listinfo/devel ___ devel mailing list devel@riot-os.org http://lists.riot-os.org/mailman/listinfo/devel
Re: [riot-devel] About function pointers
Hello, I began to use function pointers in the 'radio_driver.h' when trying to create a unified model for radio drivers. I guess it went over later to the whole netdev effort. My idea then was to have a fast, predictable call chain from the MAC layer to the physical radio transceiver functions: most MAC protocols expect to run with precise delays, and a mechanism relying on message between threads (like 'transceiver') did not fit that need. The model of driver as structs containing function pointers is the one used in Contiki: it seemed quite a natural way to handle the problem to me... In their code, the needed drivers are aliased as 'NETSTACK_xxx' macros, then functions are called by invoking 'NETSTACK_xxx.func()'. I've never seen advanced dereferencing (-) nor object-oriented like constructs in that context. As P. Nikander said, since you are supposed to know your hardware at compile time, these pointers are actually constants that should be resolved at compile (linking) time -- even with GCC. Theoretically, it should be translated by standard indirect calls at the assembler level. Could you tell us more about your previous experiments? It seems quite strange to me that such a mechanism (that seems simple to me) could impose speed and debugging penalties. The other question is how could we implement the network stack? Using a mechanism like 'transceiver', that relies on message-passing between threads, implies that there is no predictable delay for executing network functions (one has to wait for the scheduler to switch to the thread(s) that execute(s) the feature(s) you want to use). At some levels -- like between MAC and PHY -- this can be a huge disadvantage. Is there a better way to obtain deterministic/direct API calls than using the struct of function pointers scheme ?... Regards, Le 18/02/2015 11:38, Oleg Hahm a écrit : Dear remodeling IoTlers! Ludwig just made me aware that Joakim's PR for NVRAM [1] introduces function pointers as part of the device driver struct. This made me remember that there were already similar function pointers introduced as part of netdev. As I was always opposed to use function pointers in that way, I could not recall what was the reason to use them for netdev. I don't like this pseudo object oriented C style (dev-write() and the like) because we made bad experiences with it at my former company. While writing the whole HAL for our firmware there using function pointers this way, made programming pretty convenient, it turned out to become problematic speed-wise and was a nightmare to debug. Hence, I would like to trigger a fundamental discussion on this topic. Does anyone has a particular opinion on the topic why function pointer based device drivers should be a good or a bad idea? And can anyone explain to me the need of function pointers for netdev? Cheers, Oleg [1] https://github.com/RIOT-OS/RIOT/pull/2353 ___ devel mailing list devel@riot-os.org http://lists.riot-os.org/mailman/listinfo/devel -- Kévin Roussel Doctorant, projet LAR Équipe MADYNES, INRIA Nancy Grand-Est / LORIA Tél. : +33 3 54 95 86 27 kevin.rous...@inria.fr ___ devel mailing list devel@riot-os.org http://lists.riot-os.org/mailman/listinfo/devel