Unexpected behavior with (user-threads | fibers | coroutines)

1

I'm testing libcoro , a very simple and low-level library that provides coroutines more or less portable . Supposedly, it is valid for systems in production.

My code is as follows:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

#include "coro.h"

// Argumentos pasados a los 'thread's.    
struct Arg {
  const char *message;
  coro_context coro;
  struct coro_stack stack;
};

// Datos de cada 'thread'.
// Args[0] es el 'thread' principal, en el que empezamos y que controla
// al resto.
struct Arg Args[4] = {
  { NULL, { 0 }, { 0 } },
  { "Mensaje 1", { 0 }, { 0 } },
  { "Mensaje 2", { 0 }, { 0 } },
  { "Mensaje 3", { 0 }, { 0 } }
};
// Selector del 'thread' actual; usado al planificar.
volatile int idx;

// 'cuerpo' de los 'thread's.
void body( struct Arg * );
// Manejador de la interrupcion SIGALRM.
void handler( int );

int main( void ) {
  // Reservamos la memória a usar como pila por cada 'thread',
  // y los inicializamos.
  for( idx = 1; idx < 4; ++idx ) {
    coro_stack_alloc( &( Args[idx].stack ), 0 );
    coro_create( &( Args[idx].coro ),
                 (coro_func)&body,
                 (void *)&Args[idx],
                 Args[idx].stack.sptr,
                 Args[idx].stack.ssze );
  }

  signal( SIGALRM, &handler );
  idx = 4;
  coro_create( &( Args[0].coro ), NULL, NULL, NULL, 0 );

  // Planificador.
  // Los ejecutamos en secuencia, del último al primero.
  while( --idx ) {
    printf( "Dentro del bucle. idx = %d\n", idx );
    alarm( 1 );
    coro_transfer( &( Args[0].coro ), &( Args[idx].coro ) );
  }

  printf( "Fuera del bucle. idx = %d\n", idx );
  return 0;
}

void body( struct Arg *arg ) {
  printf( "%s.\n", arg->message );
  while( 1 );
  coro_transfer( &( arg->coro ), &( Args[0].coro ) );
  printf( "Saliendo de body. idx = %d", idx );
}


void handler( int sig ) {
  (void)sig;
  coro_transfer( &( Args[idx].coro ), &( Args[0].coro ) );
}

In a similar code that I used as a skeleton, which did not use alarm( ) or signal( ) , nor the while( 1 ) (without forcing the task change in the interrupt handler), it produced the following output:

  

Inside the loop. idx = 3
  Message 3.
  Inside the loop. idx = 2
  Message 2.
  Inside the loop. idx = 1
  Message 1.
  Out of the loop. idx = 0

The expected output of the displayed code is the same; the messages on the screen should be identical; however, the following is displayed:

  

Inside the loop. idx = 3
  Message 3.
  Inside the loop. idx = 2
  Message 2.

There it stops, and the CPU usage is set to 100%; that is, it stops at while( 1 ) within function body( ) ; it gives the impression that it does not enter the interrupt function.

I'm sure the bug is in my operating logic, but I do not hit the key . It is rare for to interrupt the while( 1 ) 2 times and then stop doing it. My common sense dictates that, or I would never interrupt, or I would always.

    
asked by Trauma 18.12.2016 в 23:41
source

1 answer

0

Ok, that's it. Error on my part, not correctly read libcoro documentation.

The library offers several backends , to use one or the other depending on the platform, the operating system, or if one directly does not work.

I was doing the tests with the backend CORO_ASM , supposedly the fastest in Linux. The last modification of libcoro was in 2016, so I assumed, erroneously, that backend would work in modern systems.

I've tried them all, and, on my platform (Linux, x64), it only works with CORO_CONTEXT . Because of the symptoms, there seems to be some incompatibility with the handling of signals.

Already notified in the documentation:

  

-DCORO_ASM

     

Hand coded assembly, known to work only on a few architectures / ABI: GCC + arm7 / x86 / IA32 / amd64 / x86_64 + GNU / Linux and a   few BSDs.
  Fastest choice, if it works.

The fastest ... if it works.

    
answered by 19.12.2016 / 06:14
source