Stealing a log value from a dead task Topic is solved

Technical questions regarding the XTC tools and programming with XMOS.
Post Reply
User avatar
aclassifier
Respected Member
Posts: 483
Joined: Wed Apr 25, 2012 8:52 pm
Contact:

Stealing a log value from a dead task

Post by aclassifier »

I need to be able to steal a log value from a dead task. I have reasons to believe that my communication with the RFM69 radio board [1] for some reason causes my RFM69_driver to halt. I think I have timeouts on all functional readings that would wait for a bit to appear from the radio. I communicate over SPI and use the latest version of the lib_spi. I don't have resources for the asynch version, so I run the synchronous [[distributable]] version. Therefore I have made an asynchronous version of the RFM69_driver, but it's not shown here.

What I have made is an interface function that exports a pointer to the client, and the client later on uses that pointer to ask for the data through a non-interface function. This probably "is undefined behavior for an unsafe pointer to be written from one task and read from another." (XMOS Programming Guide).

The code below still seems to work when I test it alone, but when I compile and run the same type of code (with the tasks doing all the other jobs as well) in a larger system on an xCORE-200 eXplorerKIT then byte 0 is passed over correctly always, but the other bytes are rubbish. However, I did had a row of compilations when all bytes came over correctly, but I lost that track. In other words, the code below really cannot be correct, can it?

Any ideas?

Code: Select all

// Error messages updated in http://www.teigfam.net/oyvind/home/technology/141-xc-is-c-plus-x/
// xTIMEcomposer 14.3.3

#include <platform.h>
#include <stdio.h>
#include <stdint.h> // uint8_t
#include <timer.h>  // XS1_TIMER_HZ etc
#include <iso646.h> // not, and etc.

typedef signed int time32_t;

typedef interface radio_if_t {
    // unsigned *         get_radio_log_value_ptr (void); // error: pointer return type must be marked movable, alias or unsafe         (contradicts the below)
    // unsigned * alias   get_radio_log_value_ptr (void); // error: alias pointer return type for interface functions are not supported (contradicts the above)
    // unsigned * movable get_radio_log_value_ptr (void); // RFM69_driver needs to own this at all times I would think
    unsigned    * unsafe  get_radio_log_value_ptr (void);
} radio_if_t;

unsigned get_radio_log_value (unsigned * unsafe radio_log_value_ptr) {
    unsigned return_radio_log_value;
    unsafe {
        return_radio_log_value = *radio_log_value_ptr;
        // As this simple built it works, see log below
        // On a much more complex build than this, on the xCORE-200 eXplorerKIT, only byte 0 came over correctly, the other three bytes were rubbish, however
        // there were builds where even those builds seemed to work
    }
    return return_radio_log_value;
}

void RFM69_driver (
    server radio_if_t i_radio) {

    timer      tmr;
    time32_t   time;
    unsigned   radio_log_value = 0x65432100;
    unsigned * radio_log_value_ptr = &radio_log_value; // unsafe here does not help

    tmr :> time;
    time += XS1_TIMER_HZ;

    while (1) {
        select {
            case i_radio.get_radio_log_value_ptr (void) -> unsigned * unsafe radio_log_value_ptr_ : {
                unsafe {
                    radio_log_value_ptr_ = radio_log_value_ptr;
                }
                printf ("DELIVERED address %08X\n", radio_log_value_ptr_);
            } break;

            case tmr when timerafter(time) :> void : {
                time += XS1_TIMER_HZ;
                radio_log_value++;
                printf ("NOW %08X\n", radio_log_value);
            } break;
        }
    }
}

void RFM69_client (
    client radio_if_t i_radio) {

    timer             tmr;
    time32_t          time;
    unsigned          radio_log_value;
    unsigned * unsafe radio_log_value_ptr;

    tmr :> time;
    time += (2 * XS1_TIMER_HZ);

    radio_log_value_ptr = i_radio.get_radio_log_value_ptr();

    while (1) {
        select {
            case tmr when timerafter(time) :> void: {
                time += (2 * XS1_TIMER_HZ);
                radio_log_value = get_radio_log_value(radio_log_value_ptr);
                printf ("GOT          %08X\n", radio_log_value);
            } break;
        }
    }
}

int main(void) {
    interface radio_if_t i_radio;
    par {
        RFM69_driver (i_radio);
        RFM69_client (i_radio);
    }
    return 0;
}
Here is the log when it works, when the above code runs alone on an eXplorerKIT:

Code: Select all

DELIVERED address 0007FD2C
NOW 65432101
GOT          65432101
NOW 65432102
NOW 65432103
GOT          65432103
NOW 65432104
NOW 65432105
GOT          65432105
NOW 65432106
NOW 65432107
GOT          65432107
NOW 65432108
NOW 65432109
GOT          65432109
NOW 6543210A
[1] My aquarium’s data radioed through the shelf - disclaimer: no money, salary, ads, gifts etc. involved with my blogs. Only fun and expenses


--
Øyvind Teig
Trondheim (Norway)
https://www.teigfam.net/oyvind/home/
View Solution
User avatar
akp
XCore Expert
Posts: 578
Joined: Thu Nov 26, 2015 11:47 pm

Post by akp »

If all tasks that use the variable are on the same tile I suggest GET_SHARED_GLOBAL() and SET_SHARED_GLOBAL() from module_xc_ptr
User avatar
aclassifier
Respected Member
Posts: 483
Joined: Wed Apr 25, 2012 8:52 pm
Contact:

Post by aclassifier »

Thanks akp!

They are on the same tile. I will come back when I have tested this on the startKIT with my large build. But this generates the same log as above. No interface call to get the pointer, no pointers, just a g_lobal data entry that's written to and read from:

Code: Select all

// See https://www.xcore.com/viewtopic.php?f=26&t=7073
// Also see https://www.xcore.com/viewtopic.php?t=3061 "Ways to share memory"
// xTIMEcomposer 14.3.3

#include <platform.h>
#include <stdio.h>
#include <stdint.h> // uint8_t
#include <timer.h>  // XS1_TIMER_HZ etc
#include <iso646.h> // not, and etc.
#include <xc_ptr.h> // in module_xc_ptr in sc_util-master, see https://github.com/xcore/sc_util/tree/master/module_xc_ptr 

typedef signed int time32_t;

unsigned g_radio_log_value;

void RFM69_driver (void) {

    timer    tmr;
    time32_t time;
    unsigned radio_log_value = 0x65432100;

    SET_SHARED_GLOBAL (g_radio_log_value, radio_log_value);
    tmr :> time;
    time += XS1_TIMER_HZ;

    while (1) {
        select {
            case tmr when timerafter(time) :> void : {
                time += XS1_TIMER_HZ;
                radio_log_value++;
                SET_SHARED_GLOBAL (g_radio_log_value, radio_log_value);
                printf ("NOW %08X\n", radio_log_value);
            } break;
        }
    }
}

void RFM69_client (void) {

    timer    tmr;
    time32_t time;
    unsigned radio_log_value;

    tmr :> time;
    time += (2 * XS1_TIMER_HZ);

    while (1) {
        select {
            case tmr when timerafter(time) :> void: {
                time += (2 * XS1_TIMER_HZ);
                GET_SHARED_GLOBAL (radio_log_value, g_radio_log_value);
                printf ("GOT          %08X\n", radio_log_value);
            } break;
        }
    }
}

int main(void) {
    par {
        RFM69_driver ();
        RFM69_client ();
    }
    return 0;
}
Off Topic
In xc_ptr.h I read
// Note that this function is marked as const to avoid the XC
// parallel usage checks, this is only really going to work if this
// is the *only* way the array a is accessed (and everything else uses
// the xc_ptr)

Code: Select all

inline xc_ptr array_to_xc_ptr(const char a[])
{
  xc_ptr x;
  asm("mov %0, %1":"=r"(x):"r"(a));
  return x;
}
First I cannot really see that the functions is marked as const. Would this have been inline xc_ptr array_to_xc_ptr(const char a[]) const? [1]

This is the first time I have read that this would avoid the parallel usage checks. I have not found any text about this, but would like to see one..
[1] What is meant with “const” at end of function declaration?
--
Øyvind Teig
Trondheim (Norway)
https://www.teigfam.net/oyvind/home/
User avatar
aclassifier
Respected Member
Posts: 483
Joined: Wed Apr 25, 2012 8:52 pm
Contact:

Post by aclassifier »

I have checked. SET_SHARED_GLOBAL and GET_SHARED_GLOBAL also work on the startKIT. (Sorry, I would not be able to see that from the asm code).

Simple code or in complex code, ok.

Thanks akp!
--
Øyvind Teig
Trondheim (Norway)
https://www.teigfam.net/oyvind/home/
User avatar
aclassifier
Respected Member
Posts: 483
Joined: Wed Apr 25, 2012 8:52 pm
Contact:

Post by aclassifier »

I have checked this out as solved, but would still be happy for comments on why my first code example did not work on the startKIT and the thing about const above.
--
Øyvind Teig
Trondheim (Norway)
https://www.teigfam.net/oyvind/home/
User avatar
bear118
Active Member
Posts: 37
Joined: Wed Jan 09, 2019 10:57 am

Post by bear118 »

It looks so hard. Good luck.
Post Reply