对solaris的ppoll

这段代码在Linux中编译但不在Solaris中编译,因为显然ppoll()是特定于Linux的(我在Solaris中使用GCC得到了一个未定义的符号错误)。 有任何帮助转换吗? 我不认为只使用poll()是一个好主意,但话说回来,我没有编写这段代码。 (我是用C编写命令行shell的;第一次尝试使用ncurses / C )

#include  #include  #include  #include  #include  #include  #include  #include  /** VT100 command to clear the screen. Use puts(VT100_CLEAR_SCREEN) to clear * the screen. */ #define VT100_CLEAR_SCREEN "\033[2J" /** VT100 command to reset the cursor to the top left hand corner of the * screen. */ #define VT100_CURSOR_TO_ORIGIN "\033[H" struct frame_s { int x; int y; char *data; }; static int draw_frame(struct frame_s *frame) { int row; char *data; int attrib; puts(VT100_CLEAR_SCREEN); puts(VT100_CURSOR_TO_ORIGIN); for (row = 0, data = frame->data; row y; row++, data += frame->x) { /* 0 for normal, 1 for bold, 7 for reverse. */ attrib = 0; /* The VT100 commands to move the cursor, set the attribute, and the * actual frame line. */ fprintf(stdout, "\033[%d;%dH\033[0m\033[%dm%.*s", row + 1, 0, attrib, frame->x, data); fflush(stdout); } return (0); } int main(void) { const struct timespec timeout = { .tv_sec = 1, .tv_nsec = 0 }; struct frame_s frame; struct termios tty_old; struct termios tty_new; unsigned char line[128]; unsigned int count = 0; int ret; struct pollfd fds[1]; sigset_t sigmask; struct tm *tp; time_t current_time; /* Set up a little frame. */ frame.x = 80; frame.y = 5; frame.data = malloc(frame.x * frame.y); if (frame.data == NULL) { fprintf(stderr, "No memory\n"); exit (1); } memset(frame.data, ' ', frame.x * frame.y); /* Get the terminal state. */ tcgetattr(STDIN_FILENO, &tty_old); tty_new = tty_old; /* Turn off "cooked" mode (line buffering) and set minimum characters * to zero (ie non-blocking). */ tty_new.c_lflag &= ~ICANON; tty_new.c_cc[VMIN] = 0; /* Set the terminal attributes. */ tcsetattr(STDIN_FILENO, TCSANOW, &tty_new); /* Un-mask all signals while in ppoll() so any signal will cause * ppoll() to return prematurely. */ sigemptyset(&sigmask); fds[0].events = POLLIN; fds[0].fd = STDIN_FILENO; /* Loop forever waiting for key presses. Update the output on every key * press and every 1.0s (when ppoll() times out). */ do { fds[0].revents = 0; ret = ppoll(fds, sizeof(fds) / sizeof(struct pollfd), &timeout, &sigmask); if (fds[0].revents & POLLIN) { ret = read(STDIN_FILENO, &line[count], sizeof(line) - count); if (ret > 0) { line[count + ret] = '\0'; if (strcmp(&line[count], "\033[A") == 0) { snprintf(frame.data, frame.x, "up"); count = 0; } else if (strcmp(&line[count], "\033[B") == 0) { snprintf(frame.data, frame.x, "down"); count = 0; } else if (line[count] == '\n') { snprintf(frame.data, frame.x, "entered: %s", line); count = 0; } else { count += ret; } } } /* Print the current time to the output buffer. */ current_time = time(NULL); tp = localtime(&current_time); strftime(&frame.data[1 * frame.x], frame.x, "%Y/%m/%d %H:%M:%S", tp); /* Print the command line. */ line[count] = '\0'; snprintf(&frame.data[(frame.y - 1) * frame.x], frame.x, "$ %s", line); draw_frame(&frame); } while (1); /* Restore terminal and free resources. */ tcsetattr(STDIN_FILENO, TCSANOW, &tty_old); free(frame.data); return (0); } 

你现在可以在这里用poll()替换ppoll()的原因不是因为提供给ppoll()的信号掩码是空的 – 这是通常的情况 – 但是因为ppoll()之前的信号掩码是也可能是空的。

这是唯一可能的,因为shell目前不会尝试处理任何信号。 只要您想要处理shell处理信号,就需要使用以下序列:

 /* Block all signals */ sigprocmask(SIG_SETMASK, all_signals); /* Check and handle any signals that have occured. */ check_signals(); /* Wait for activity on a file descriptor or a signal */ ppoll(..., empty_set); 

ppoll()在这里是必要的,因为否则存在竞争条件 – 信号可能在check_signals();之间到达check_signals();poll()调用,这将被错过。 因此,信号在此期间被阻止,然后在ppoll() primefaces地解锁。

由于ppoll()是Solaris未提供的GNU扩展,因此您需要更改代码以使用pselect() ,它是POSIX标准函数。


要将代码转换为使用pselect() ,请将循环的开头替换为:

 do { fd_set rdset; int nfds = STDIN_FILENO + 1; FD_ZERO(&rdset); FD_SET(STDIN_FILENO, &rdset); ret = pselect(nfds, &rdset, NULL, NULL, &timeout, &sigmask); if (ret < 0) { if (errno == EINTR) continue; else break; } if (FD_ISSET(STDIN_FILENO, &rdset)) { ret = read(STDIN_FILENO, &line[count], sizeof(line) - count); /* ... */ 

然后,您可以删除变量fds ,因为不再需要它。

请注意,我添加了代码以检查pselect()的返回值是否也出错 - 旧代码应该对ppoll()执行相同的操作。

您没有使用亚毫秒超时,溢出(int)或非空sigmask的超时,因此poll()可以正常使用。