将 C 代码从 POSIX 移植到 Windows(siginfo 问题) [英] Porting a C code to Windows from POSIX (problem with siginfo)

查看:60
本文介绍了将 C 代码从 POSIX 移植到 Windows(siginfo 问题)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在 Windows 下本地编译程序MRCC"(为 Linux 开发).该程序主要是用Fortran编写的,而与系统的接口据我所知是用C编写的.除了一个导致问题的 C 源文件外,所有源文件都可以使用 mingw64-gnu 编译器成功编译.问题来自类型siginfo_t".在 mingw64 中没有实现.

I am trying to compile the program 'MRCC' (developed for Linux) natively under Windows. The program is mainly written in Fortran, while the interface with the system is written in C as far as I can tell. All of the source files compile successfully with mingw64-gnu compilers except one C source that causes problems. The problem is from the type "siginfo_t" which is not implemented in mingw64.

源文件(signal.c)是:

The source file (signal.c) is:

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>


#ifdef __cplusplus
extern "C" {
#endif

#ifdef INT64
void mrccend_(long*);
void dmrccend_(long*);
long ERROR_SIGTERM = -1;
long ERROR_SIGSEGV = -2;
#else
void mrccend_(int*);
void dmrccend_(int*);
int ERROR_SIGTERM = -1;
int ERROR_SIGSEGV = -2;
#endif

void parent_sigterm_(int, siginfo_t *, void *);
void child_sigterm_(int, siginfo_t *, void *);
void child_sigsegv_(int, siginfo_t *, void *);
void sendSignalToChildren(int);

static struct sigaction old_act;

void signalinit_() {
// initialise dmrcc's responses to signals
   struct sigaction act_term;
   memset(&act_term, '\0', sizeof(act_term));
   act_term.sa_sigaction = &parent_sigterm_;
   act_term.sa_flags = SA_SIGINFO;
   sigaction(SIGTERM, &act_term, NULL);
}

void parent_sigterm_(int signum, siginfo_t *siginfo, void *context) {
// initialise response to signal SIGTERM
   pid_t pid_parent;
   char pidchar[10];
   char command[40];

   pid_parent = getpid();
   sprintf(pidchar, "%d", pid_parent);

   printf("\n Program dmrcc recieved SIGTERM\n"); fflush(stdout);

   sendSignalToChildren(SIGTERM);
   sleep(5);
   sendSignalToChildren(SIGKILL);

   printf("\n Program dmrcc terminating\n"); fflush(stdout);
   dmrccend_(&ERROR_SIGTERM);
}

void sendSignalToChildren(int sig) {
   int ownPid = getpid();
   int pid, numPids = 0;
   int *pids;
   FILE *pidfile = fopen("pids", "r");
   if (pidfile == NULL) {
      printf("Error: Could not open pids file\n");
      return;
   }

   // number of running processes other than the current process
   while (fscanf(pidfile, "%d", &pid) != EOF) {
      if (pid != ownPid) {
         numPids++;
      }
   }
   rewind(pidfile);

   // read other process' PIDs
   pids = (int *)malloc(numPids * sizeof(int));
   int i = -1;
   while (fscanf(pidfile, "%d", &pid) != EOF) {
      if (pid != ownPid) {
         pids[++i] = pid;
      }
   }

   // send signal sig to processes
   printf("\n Sending signal %2d to child processes\n", sig); fflush(stdout);
   for (i = 0; i < numPids; i++) {
      kill((pid_t)pids[i], sig);
   }
   
   fclose(pidfile);
   free(pids);
}

void signalinitchild_() {
// initialise child's responses to signals
   struct sigaction act_term;
   memset (&act_term, '\0', sizeof(act_term));
   act_term.sa_sigaction = &child_sigterm_;
   act_term.sa_flags = SA_SIGINFO;
   sigaction(SIGTERM, &act_term, NULL);

   struct sigaction act_segv;
   memset (&act_segv, '\0', sizeof(act_segv));
   act_segv.sa_sigaction = &child_sigsegv_;
   act_segv.sa_flags = SA_SIGINFO;
   sigaction(SIGSEGV, &act_segv, &old_act);
}

void child_sigterm_(int signum, siginfo_t *siginfo, void *context) {
// initialise child's response to signal SIGTERM
   mrccend_(&ERROR_SIGTERM);
}

void child_sigsegv_(int signum, siginfo_t *siginfo, void *context) {
// initialise child's response to signal SIGSEGV
   mrccend_(&ERROR_SIGSEGV);
   if(old_act.sa_flags & SA_SIGINFO)
   {
      (*old_act.sa_sigaction)(signum, siginfo, context);
   } 
   else 
   { 
      (*old_act.sa_handler)(signum);
   }
}

#ifdef __cplusplus
}
#endif

Windows 原生支持 SIGTERM 和 SIGSEGV.但是, SIGINFO 不是,因此未定义 siginfo_t 类型.编译器也会在 sigaction 处抛出错误.我知道我需要更改代码,以便它使用 Windows API 而不是 POSIX API.但是,我不知道该怎么做.我可以用 void 类型替换 siginfo_t 类型吗?我可以对 sigaction 做些什么?

SIGTERM and SIGSEGV are supported in Windows natively. However, SIGINFO is not, so siginfo_t type is not defined. Ther compiler also throws error at the sigaction. I understand that I need to change the code so that it uses Windows API instead of POSIX API. However, I am not sure how to do that. Can I just replace the siginfo_t type with void type? And what can I do about sigaction?

[我正在使用的来自 mingw64 的 signal.h 标头粘贴在 这里 ]

[The signal.h header from mingw64 that I am using is pasted here ]

推荐答案

重写它以在 Windows 上使用 signal.

Rewrite it to use signal on Windows.

(在幕后,这就是 Gnulib 为 mingw 平台所做的:根据 signal 重新实现 sigaction,使用定义但有效的虚拟 siginfo_t> 结构来解决编译问题.)

(Under the hood, that's what Gnulib does for mingw platforms: reimplement sigaction in terms of signal, with a defined but effectively dummy siginfo_t structure to get past compilation issues.)

虽然标准做法是使用 sigaction 而不是 signala> — 事实上,我想说现在使用 signal 几乎是一种疏忽 — 你必须使用你拥有的东西,而且你没有一个符合 SA_SIGINFO 的实现.您不必担心重新安装处理程序,因为您打算根据您处理的信号终止.

While standard practice is to use sigaction in preference to signal — indeed, I'd say using signal is almost negligent these days — you've got to work with what you have, and you don't have a conforming SA_SIGINFO implementation. You don't have to worry about reinstalling handlers, since you intend to terminate upon the signals you do handle.

所以,当你完成后,它看起来像这样:

So, when you're done it will look something like this:

static void (*old_segv_handler)(int) = NULL;

void parent_sigterm_(int s) { ... }

void child_sigterm_(int s) { ... }

void child_segv_(int s) {
    mrccend_(...);
    old_segv_handler(s); // FIXME: handle SIG_IGN, SIG_DFL, SIG_ERR
}    

void signalinit_() {
    signal(SIGTERM, parent_sigterm_);
}
void signalinitchild_() {
    signal(SIGTERM, child_sigterm_);
    old_segv_handler = signal(SIGSEGV, child_segv_);
}

请解决上面的 FIXME,并在您的父 SIGTERM 处理程序中删除那些不安全的 stdio 调用.

Please do address the FIXME above and remove those unsafe stdio calls in your parent SIGTERM handler.

这篇关于将 C 代码从 POSIX 移植到 Windows(siginfo 问题)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆