1

I installed Arch Arm onto an Rpi3, then rsync'd sysroot to an x86_64 Arch Linux installed on a Lenovo thinkpad.

I then installed the arm-linux-gnueabihf Linaro cross compiler

To avoid any problems I used absolute paths in compilation:

/home/sameh/Rpi/Compiler/gcc-linaro-7.2.1-2017.11-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc\
 --sysroot=/home/sameh/Rpi/Arch/ArmV7/root\
 -o stress stress.c -lm

The code compiles fine, however when I execute it on the Rpi3 it has no output.

It doesn't freez the Pi, I can ps aux and see the child processes created by fork().

But none of the debug statements are printed and none of the processes exit.

Edit

This code is based on the stress library. For an MCVE I minimized it to only the hogcpu function

#include <ctype.h>
#include <errno.h>
#include <libgen.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include <sys/wait.h>

int hogcpu (void);

int
hogcpu (void)
{
  for(int i=0; i < 1000000; i++)
    sqrt (rand ());
  return 0;
}

int main()
{

  struct timespec start, end;
  double cpu_time_used;
  int pid, children = 0, retval = 0;
  long forks;
  int do_dryrun = 0;
  long long do_backoff = 3000;

  long long do_cpu = 1;
  long long backoff, timeout = 0;

  /* Calculate the backoff value so we get good fork throughput.  */
  backoff = do_backoff * forks;

  clock_gettime(CLOCK_REALTIME, &start); 

  while ((forks = (do_cpu + do_io + do_vm + do_hdd)))
  {
    if (do_cpu)
    {
      switch (pid = fork ())
        {
        case 0:            /* child */
          alarm (timeout);
          usleep (backoff);
          exit (hogcpu ());
        case -1:           /* error */
          break;
        default:
          ++children;
        }
      --do_cpu;
    }

  }
  /* Wait for our children to exit.  */
  while (children)
  {
    int status, ret;

    if ((pid = wait (&status)) > 0)
    {
      --children;
      if (WIFEXITED (status))
      {
        if ((ret = WEXITSTATUS (status)) == 0)
        {
          printf( "<-- worker %i returned normally\n", pid);
        }
        else
        {
          printf( "<-- worker %i returned error %i\n", pid, ret);
          ++retval;
          printf( "now reaping child worker processes\n");
          if (signal (SIGUSR1, SIG_IGN) == SIG_ERR)
            printf( "handler error: %s\n", strerror (errno));
          if (kill (-1 * getpid (), SIGUSR1) == -1)
            printf( "kill error: %s\n", strerror (errno));
        }
      }
    }
  }

  clock_gettime(CLOCK_REALTIME, &end); 
  cpu_time_used = (end.tv_nsec = start.tv_nsec) / 1000000000.0;
  /* Print final status message.  */
  if (retval)
  {
    printf( "failed run completed in %.2f s\n", cpu_time_used);
  }
  else
  {
    printf( "successful run completed in -- %.2f s\n", cpu_time_used);
  }

  exit (retval);
}

I can successfully compile and execute it on the the Pi with:

[alarm@control ~]$ gcc stress.c -o stress -lm
[alarm@control ~]$ ./stress 
<-- worker 16834 returned normally
<-- worker 16835 returned normally
<-- worker 16836 returned normally
successful run completed in -- 0.90 s

However, when cross compiled and transferred to the Pi, the behavior described above is what I am seeing.

Note

This may well have to do with the clock_gettime call. When I replace this with a clock() function call, I can compile and run it on the laptop, but compiling on the Pi with gcc has the same behavior above.

When using clock_gettime and compiling on the Pi, it works fine.

Sam Hammamy
  • 10,819
  • 10
  • 56
  • 94

1 Answers1

1

The issue here was how the long forks; variable was initialized. I am not well versed in compilers, but because forks was not initialized, the calculation backoff = do_backoff * forks; resulted in a random negative number.

This blocked the call usleep (backoff); from finishing. So initializing forks to 1 fixed the problem.

I would have thought that forks should have been initialized to 0 by the compiler as past of the bss_data so I am not sure why it didn't. Probably need more research into that part, but the code executes fine now with cross compiling.

Sam Hammamy
  • 10,819
  • 10
  • 56
  • 94
  • 1
    "I would have thought that `forks` should have been initialized to 0 by the compiler as past of the `bss_data` so I am not sure why it didn't" `forks` is a local variable, if you leave it uninitialized it will get whatever happens to be on the stack/register in its place; more in abstract, the C standard says that it's undefined behavior to read from an uninitialized variable. `.bss` is for globals (more precisely: for static storage duration variables, i.e. globals + `static` locals, which are globals in disguise), which are guaranteed to be 0 if not explicitly initialized. – Matteo Italia May 05 '18 at 11:13
  • 1
    By the way, this would have been spotted immediately when compiling with `-Wall -Wextra -O3`. You should get in the habit of always compiling with most warnings enabled to avoid these traps. – Matteo Italia May 05 '18 at 11:17
  • 1
    Nice! Thanks for the tip! – Sam Hammamy May 05 '18 at 11:25
  • https://godbolt.org/g/8SpbWH for example. BTW in your original code `do_io`, `do_vm` and `do_hdd` are missing. – Matteo Italia May 05 '18 at 12:45