1

更新 1:此问题已更新,以消除多线程,简化其范围。原来的问题popen在主线程中,pclose子进程在不同的线程中。通过在同一个(主)线程中执行popenand ,所询问的问题可以更简单地重现。pclose

更新 2:在如何检查 libc 版本的响应者的帮助下?,我想我已经确定正在使用的 libc 是 uClibc 0.9.30。

下面的代码popen是主线程中的一个脚本,稍等片刻,然后pclose是同一个主线程中的子进程。该程序针对多个交叉目标进行了交叉编译。

可执行文件的代码:

// mybin.c
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>

static FILE* logFile = NULL;

static void logInit( const char* fmt );
static void log_( const char* file, int line, const char* fmt, ... );
static void logCleanup();

#define log(fmt, ...) log_( __FILE__, __LINE__, fmt, ##__VA_ARGS__ )

int main( int argc, char* argv[] )
{
  logInit( "./mybin.log" );

  {
    bool success = false;
    FILE* f;

    if ( ! (f = popen( "./myscript", "r" )) )
    {
      log( "popen error: %d (%s)", errno, strerror( errno ) );
      goto end;
    }

    log( "before sleep" );
    sleep( 1 );
    log( "after sleep" );
    pclose( f );
    log( "after pclose" );

    success = true;
  }

end:

  log( "At end" );
  logCleanup();

  return 0;
}

/** Initializes logging */
static void logInit( const char* file )
{
  logFile = fopen( file, "a" );
}

/** Logs timestamp-prefixed, newline-suffixed printf-style text */
static void log_( const char* file, int line, const char* fmt, ... )
{
  //static FILE* logOut = logFile ? logFile : stdout;
  FILE* logOut = logFile ? logFile : stdout;

  time_t t = time( NULL );
  char fmtTime[16] = { '\0' };
  struct tm stm = *(localtime( &t ));
  char logStr[1024] = { '\0' };
  va_list args;

  va_start( args, fmt );
  vsnprintf( logStr, sizeof logStr, fmt, args );
  va_end( args );
  strftime( fmtTime, sizeof fmtTime, "%Y%m%d_%H%M%S", &stm );

  fprintf( logOut, "%s %s@%d %s\n", fmtTime, file, line, logStr );
}

/** Cleans up after logInit() */
static void logCleanup()
{
  if ( logFile ) { fclose( logFile ); }

  logFile = NULL;
}

剧本:

#! /bin/bash

# mybin

rm -f ./myscript.log
for i in {1..10}; do echo "$(date +"%Y%m%d_%H%M%S") script is running" >> ./myscript.log; sleep 1; done

预期的行为是编译的可执行文件在子进程中生成脚本的执行,等待其完成,然后退出。这在包括 x86、x64 和 ARM 在内的许多跨目标上都得到了满足。以下是满足预期行为的示例架构、编译和相应的日志:

$ uname -a
Linux linuxbox 5.4.8-200.fc31.x86_64 #1 SMP Mon Jan 6 16:44:18 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

汇编:

$ gcc --version && gcc -g ./mybin.c -lpthread -o mybin
gcc (GCC) 9.2.1 20190827 (Red Hat 9.2.1-1)
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$

mybin.log:

20200705_200950 ./mybin.c@33 before sleep
20200705_200951 ./mybin.c@35 after sleep
20200705_201000 ./mybin.c@37 after pclose
20200705_201000 ./mybin.c@44 At end

myscript.log:

20200705_200950 script is running
20200705_200951 script is running
20200705_200952 script is running
20200705_200953 script is running
20200705_200954 script is running
20200705_200955 script is running
20200705_200956 script is running
20200705_200957 script is running
20200705_200958 script is running
20200705_200959 script is running

然而,在一个目标上,发生了一件奇怪的事情:pclose提前返回:在脚本开始运行之后,但在它完成运行之前很久——为什么?以下是观察到意外行为的问题架构、交叉编译器标志和相应的日志:

$ uname -a
Linux hostname 2.6.33-arm1 #2 Wed Jul 1 23:05:25 UTC 2020 armv7ml GNU/Linux

交叉编译:

$ /path/to/toolchains/ARM-cortex-m3-4.4/bin/arm-uclinuxeabi-gcc --version
arm-uclinuxeabi-gcc (Sourcery G++ Lite 2010q1-189) 4.4.1
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ /path/to/toolchains/ARM-cortex-m3-4.4/bin/arm-uclinuxeabi-gcc -O2 -Wall   -fno-strict-aliasing  -Os -D__uClinux__ -fno-strict-aliasing -mcpu=cortex-m3 -mthumb  -g -ffunction-sections -fdata-sections -I/path/to/toolchains/ARM-cortex-m3-4.4/usr/include/ -Wl,--gc-sections -Wl,-elf2flt=-s -Wl,-elf2flt=8192 -I/path/to/toolchains/ARM-cortex-m3-4.4/sysroot/usr/include -I/path/to/libs/ARM-cortex-m3-4.4/usr/include/ -L/path/to/toolchains/ARM-cortex-m3-4.4/sysroot/usr/lib  -lrt -L/path/to/libs/ARM-cortex-m3-4.4/usr/lib -L/path/to/libs/ARM-cortex-m3-4.4/lib -o mybin ./mybin.c  -lrt -lpthread
$

mybin.log:

20200705_235632 ./mybin.c@33 before sleep
20200705_235633 ./mybin.c@35 after sleep
20200705_235633 ./mybin.c@37 after pclose
20200705_235633 ./mybin.c@44 At end

myscript.log:

20200705_235632 script is running

我的问题的要点是:为什么pclose过早返回,为什么只在这个交叉目标上?

评论和研究让我认为这是变体/版本中的一个错误libc- 如果了解该主题的人可以帮助确认是否是这种情况,那就太好了。


不是pclose() 在多线程环境中过早返回的副本(Solaris 11)

4

0 回答 0