Page 2 of 2

Re: Communication between two tasks

Posted: Wed Mar 22, 2017 4:07 pm
by peter
There is a possibility that the pointer you are passing is going out of scope in the case where it is going wrong and being changed on the stack. You really should ensure that the sender stays active until the print has finished by sending the pointer back once it has finished printing and waiting for that.

Re: Communication between two tasks

Posted: Wed Mar 22, 2017 4:37 pm
by cschopges
Thanks, that was the problem.

But why should I send the pointer back since I'm not interested in the content? How will task2 know if it can send the next pointer or it should receive the previously send one?

Re: Communication between two tasks

Posted: Thu Mar 23, 2017 9:08 am
by peter
There is no reason to pass the pointer back necessarily, just a suggestion of a way to ensure that the printing had completed before the other task exited.

Re: Communication between two tasks

Posted: Wed Mar 21, 2018 3:40 pm
by zhy44th
cschopges wrote:A quick example:

Code: Select all

#include <print.h>

typedef struct my_struct {
  unsigned id1;
  unsigned id2;
  unsigned id3;
  unsigned id4;
  char data[8];
} my_struct;

void print_msg(my_struct f, char prepend[]){
  printstr(prepend);
  printhex(f.id3);
  printstr("\t");
  if(f.id2)
    printstr(" : Ext\t");
  else
    printstr(" : Std\t");
  if(f.id1)
    printstr(" : R \t");
  else
    printstr(" : D \t");
  printint(f.id4);
  printstr("\t");
  if(!f.id1)
    for(unsigned i=0;i<f.id4;i++){
      printhex(f.data[i]);
      printstr("\t");
    }
  printstrln("");
}

void task1(streaming chanend c_to)
    my_struct * unsafe test;
    unsafe{
        c_to :> test;
        print_msg(*test, "received: ");
    }

}

void task2(streaming chanend c_to){
    my_struct rx_buff;
    unsafe{
        my_struct * unsafe test = &rx_buff;

        test->id1 = 0;
        test->id2 = 1;
        test->id3 = 0x18da29F1;
        test->id4 = 3;
        test->data[0] = 0x02  ;
        test->data[1] = 0x21;
        test->data[2] = 0x01;
        test->data[3] = 0x0;
        test->data[4] = 0x0;
        test->data[5] = 0x0;
        test->data[6] = 0x0;
        test->data[7] = 0x0;

        //print_msg(*test, "send: ");
        c_to <: test;
    }
}

int main(){
    streaming chan c_to;
    par{
        task1(c_to);
        task2(c_to);
    }
    return 0;
}
If I uncomment //print_msg(*test, "send: "); it works, otherwise not. Why? I can't figure it out.
Moreover, does everything needs to be in an unsafe region?

Thanks for your code.
Why the structure pointer transfer fast than array's pointer?

Re: Communication between two tasks

Posted: Thu Mar 22, 2018 1:03 pm
by robertxmos
Hi zhy44th,

Regarding structure pointer and array transfer, it depends :-)
Arrays and references will implicitly use memcpy type functions (remote_memcpy for when code is on another tile) and optimise them.
Also, if it can't be done at compile time, array access will be range checked too.
Pointers (smart and unsafe) will only work for shared memory and you control every action.
The value and reference semantics will be slightly different too - you get what you ask for.

Regarding the code, there are a couple of problems.
First, the function task2 will complete and exit, unwinding its stack and hence leave the sent pointer 'test' dangling - not nice!
To fix this you need to handshake with task1 the ownership of 'rx_buffer' - see earlier answer.

The second is more unfortunate.
The compiler will look at your code and decide that rx_buffer's address is used to initialise a pointer, but the pointer is never dereferenced.
Hence, there is no need to do the initialisation of the structure - and your set up code is promptly optimised away.
This is a bug in the compiler - passing a pointer over a channel suggests it will be dereferenced, hence the optimisation should be prevented.

The work around is to prevent the compiler doing the optimisation by:
1. Build with -O0 (bad idea)
2. pass the structure's pointer to a function (as you do with print_msg) AND make sure it can't see how the pointer is used (compilers can be very sneaky).

#2 may be achieved by placing the creation and initiation of the structure in one file (compilation unit) and the use/sending in another file viz:
// file1.xc

Code: Select all

void task1(streaming chanend c_to) {
...
    c_to :> test;
    print_msg(test, "received: ");
    c_to <: test;
}

// Can only see that the structure 'might' be dereferenced in sendBuffer() - hence no optimisation of fields allowed.
unsafe void sendBuffer(streaming chanend c_to,  my_struct * unsafe test);

void task2(streaming chanend c_to){
    my_struct rx_buff;
    unsafe{
        my_struct * unsafe test = &rx_buff;
        test->id1 = 0;
...
       sendBuffer(c_to, test);
    }
}
//file2.xc

Code: Select all

unsafe void sendBuffer(treaming chanend c_to,  my_struct * unsafe test) {
  c_to <: test;
  c_to :> test;
}
The downside is the extra file and the overhead of a function call.
You can't inline the function as this would allow the compiler to see and hence optimise!
I'm sure there are other imaginative ways you could solve your original problem if you don't like the above.

robert

Re: Communication between two tasks

Posted: Thu Mar 22, 2018 7:55 pm
by robertxmos
FYI
This is a bug in the compiler - passing a pointer over a channel suggests it will be dereferenced, hence the optimisation should be prevented.
The bug has been fixed for the future release 14.3.3 and 14.4.0.