- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我目前正在做一个主要是为了好玩的项目,试图编写一个简单的终端模拟器。到目前为止,我想要做的只是拥有一个只转发终端命令的“代理进程”。到目前为止,当我使用下面的代码调用/usr/bin/nano 时,这似乎有效。
然而,当我尝试用 emacs 做同样的事情时,我遇到了一个 heisenbug:有时效果很好,但大部分情况下效果不好:调整大小有效,但只要我键入任何内容,我的进程就会暂停,就好像我按下Ctrl+z(我当然没有这样做)。
emacs 的 strace 是一个序列:
ioctl(6, FIONREAD, [0]) = 0
poll([{fd=7, events=POLLIN}], 1, 0) = 0 (Timeout)
read(7, 0x7fff078de1d0, 16) = -1 EAGAIN (Resource temporarily unavailable)
select(8, [6 7], NULL, NULL, {100000, 0}) = ? ERESTARTNOHAND (To be restarted)
--- SIGIO (I/O possible) @ 0 (0) ---
rt_sigreturn(0x1d) = -1 EINTR (Interrupted system call)
暂停时我的流程是:
rt_sigaction(SIGTSTP, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGTSTP, {0x7f8964468b50, [], SA_RESTORER|SA_RESTART, 0x7f8963ea54a0}, NULL, 8) = 0
rt_sigaction(SIGINT, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGINT, {0x7f8964468a80, [], SA_RESTORER|SA_RESTART, 0x7f8963ea54a0}, NULL, 8) = 0
rt_sigaction(SIGTERM, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGTERM, {0x7f8964468a80, [], SA_RESTORER|SA_RESTART, 0x7f8963ea54a0}, NULL, 8) = 0
rt_sigaction(SIGWINCH, NULL, {0x401088, [WINCH], SA_RESTORER|SA_RESTART, 0x7f8963ea54a0}, 8) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig -icanon -echo ...}) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig -icanon -echo ...}) = 0
ioctl(1, SNDCTL_TMR_STOP or TCSETSW, {B38400 opost -isig -icanon -echo ...}) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost -isig -icanon -echo ...}) = 0
select(4, [0 3], [], NULL, NULL) = 1 (in [0])
read(0, 0x7fffafd46890, 4096) = ? ERESTARTSYS (To be restarted)
--- SIGTTIN (Stopped (tty input)) @ 0 (0) ---
--- SIGTTIN (Stopped (tty input)) @ 0 (0) ---
read(0, 0x7fffafd46890, 4096) = ? ERESTARTSYS (To be restarted)
--- SIGTTIN (Stopped (tty input)) @ 0 (0) ---
--- SIGTTIN (Stopped (tty input)) @ 0 (0) ---
read(0, 0x7fffafd46890, 4096) = ? ERESTARTSYS (To be restarted)
--- SIGTTIN (Stopped (tty input)) @ 0 (0) ---
--- SIGTTIN (Stopped (tty input)) @ 0 (0) ---
我的源代码,用-lutil -lncurses编译:
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdbool.h>
#include <spawn.h>
#include <fcntl.h>
#include <sys/select.h>
#include <stdarg.h>
#include <unistd.h>
#include <stdio.h>
#include <malloc.h>
#include <curses.h>
#include <sys/ioctl.h>
#include <signal.h>
#ifdef __GNUC__
# define likely(x) __builtin_expect((x),1)
# define unlikely(x) __builtin_expect((x),0)
#else
# define likely(x) (x)
# define unlikely(x) (x)
#endif
int mpt; /* master pty */
pid_t pid = 0; /* child pid */
bool childexit = false;
int max (int ini, ...) {
/* the maximum of positive integers, terminated with -1 */
va_list ap;
va_start(ap, ini);
int ret = -1;
while (ini != -1) {
ret = (ret < ini) ? ini : ret;
ini = va_arg(ap, int);
}
va_end(ap);
return ret;
}
/* atexit */
void close_child (void) {
if (! childexit) {
kill (pid, SIGTERM);
}
}
void reset_term (void) {
endwin();
}
/* signal handlers */
void sigwinch (int sig) {
(void) sig;
struct winsize w;
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1) {
ioctl(mpt, TIOCSWINSZ, &w);
}
}
void sigchld (int sig) {
(void) sig;
//childexit = true;
exit(EXIT_SUCCESS);
}
void sigusr1 (int sig) {
(void) sig;
struct winsize w;
ioctl(STDIN_FILENO, TIOCGWINSZ, &w);
w.ws_row = 25;
w.ws_col = 25;
}
int main (void) {
atexit(close_child);
atexit(reset_term);
char* spawnedArgs[] = { "/usr/bin/emacs", "-nw", NULL };
char* spawnedEnv[] = { "TERM=xterm", NULL };
size_t slave_len = 128 * sizeof(char);
char* slave = malloc (slave_len);
if (slave == NULL) {
fprintf(stderr, "Cannot allocate slave var");
exit(EXIT_FAILURE);
}
mpt = posix_openpt(O_RDWR | O_NOCTTY);
if (mpt < 0) {
perror("Cannot open Master");
exit(EXIT_FAILURE);
}
if (grantpt(mpt) < 0) {
perror("Cannot grant Terminal");
exit(EXIT_FAILURE);
}
if (unlockpt(mpt) < 0) {
perror("Cannot unlock Terminal");
exit(EXIT_FAILURE);
}
while ((ptsname_r(mpt, slave, slave_len)) != 0) {
int e = errno;
if (e == ERANGE) {
slave_len *= 2;
slave = realloc(slave, slave_len);
if (slave == NULL) {
fprintf(stderr, "Cannot reallocate slave var\n");
exit(EXIT_FAILURE);
}
} else {
fprintf(stderr, "Cannot get name of terminal: %s\n", strerror(e));
exit(EXIT_FAILURE);
}
}
int slavefd = open(slave, O_RDWR | O_NOCTTY);
if (slavefd < 0) {
perror("Cannot open Slave");
exit(EXIT_FAILURE);
}
posix_spawn_file_actions_t action;
posix_spawnattr_t attrs;
sigset_t set;
sigemptyset(&set);
posix_spawnattr_setsigmask(&attrs, &set);
posix_spawnattr_setflags(&attrs, POSIX_SPAWN_SETSIGMASK);
posix_spawn_file_actions_init(&action);
posix_spawn_file_actions_adddup2(&action, slavefd, STDOUT_FILENO);
posix_spawn_file_actions_adddup2(&action, slavefd, STDIN_FILENO);
posix_spawnp(&pid, spawnedArgs[0], &action, &attrs, spawnedArgs, spawnedEnv);
fd_set rfds, wfds;
int sel, nfds;
char mystdin[4096], yourstdout[4096];
int mystdindef = 0, yourstdoutdef = 0;
signal(SIGWINCH, sigwinch);
signal(SIGCHLD, sigchld);
signal(SIGUSR1, sigusr1);
initscr (); raw (); noecho ();
while (1) {
begin_select_loop:
nfds = 0;
FD_ZERO(&rfds);
FD_ZERO(&wfds);
/* read if buffers are empty, write if buffers are filled */
if (mystdindef == 0) {
FD_SET(STDIN_FILENO, &rfds);
nfds = max(nfds, STDIN_FILENO, -1);
} else {
FD_SET(mpt, &wfds);
nfds = max(nfds, mpt, -1);
}
if (yourstdoutdef == 0) {
FD_SET(mpt, &rfds);
nfds = max(nfds, mpt, -1);
} else {
FD_SET(STDOUT_FILENO, &wfds);
nfds = max(nfds, STDOUT_FILENO, -1);
}
sel = select(1 + nfds, &rfds, &wfds, NULL, NULL);
if (sel < 0) {
int e = errno;
if (unlikely(e == EINTR)) {
/* A signal has interrupted us. Well, I guess this might be
one of the few legit uses of goto, since C99 has no good
mechanism for continuations yet. */
goto begin_select_loop;
} else {
fprintf(stderr, "Error calling select: %s\n", strerror(e));
exit(EXIT_FAILURE);
}
}
if (FD_ISSET(STDIN_FILENO, &rfds)) {
mystdindef = read (STDIN_FILENO, mystdin, sizeof(mystdin));
if (unlikely(mystdindef == -1)) {
perror("Reading from stdin");
exit(EXIT_FAILURE);
} else if (unlikely(mystdindef == 0)) {
/* EOF */
//exit(EXIT_SUCCESS);
}
}
if (FD_ISSET(mpt, &rfds)) {
yourstdoutdef = read (mpt, yourstdout, sizeof(mystdin));
if (unlikely(yourstdoutdef == -1)) {
perror("Reading from master");
exit(EXIT_FAILURE);
} else if (unlikely(yourstdoutdef == 0)) {
/* EOF */
//exit(EXIT_SUCCESS);
}
}
if (FD_ISSET(STDOUT_FILENO, &wfds)) {
int written = write(STDOUT_FILENO, yourstdout, yourstdoutdef);
if (unlikely(written == -1)) {
perror("Writing to stdout");
exit(EXIT_FAILURE);
} else if (unlikely(written < yourstdoutdef)) {
memmove(yourstdout, yourstdout + written, yourstdoutdef -= written );
} else {
yourstdoutdef = 0;
}
}
if (FD_ISSET(mpt, &wfds)) {
int written = write(mpt, mystdin, mystdindef);
if (unlikely(written == -1)) {
perror("Writing to stdout");
exit(EXIT_FAILURE);
} else if (unlikely(written < mystdindef)) {
memmove(mystdin, mystdin + written, mystdindef -= written );
} else {
mystdindef = 0;
}
}
}
}
如果有任何帮助,我将不胜感激,我真的不知道会发生什么。
最佳答案
您不通过 posix_spawnattr_init()
初始化 posix_spawnattr_t
对象(可能导致使用意外属性)并且不破坏 posix_spawnattr_t
或 posix_spawn_file_actions_t
对象。
子进程既没有伪终端作为它的 stderr (fd 2),也没有作为它的控制终端。因此,它将部分表现得好像附加到原始 tty 而不是新的。
前者很容易通过另一个 dup2 修复。后者需要调用 setsid()
,在子进程中调用非标准函数,如 tcsetsid()
或 TIOCSCTTY
ioctl;因此,您需要从 posix_spawnp()
移动到 fork()
和 execve()
。
如果您不介意使用更多非标准函数,您可以使用login_tty()
或forkpty()
来简化代码。
关于c - 写入 emacs 时进程有时会暂停,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14793202/
SQLite、Content provider 和 Shared Preference 之间的所有已知区别。 但我想知道什么时候需要根据情况使用 SQLite 或 Content Provider 或
警告:我正在使用一个我无法完全控制的后端,所以我正在努力解决 Backbone 中的一些注意事项,这些注意事项可能在其他地方更好地解决......不幸的是,我别无选择,只能在这里处理它们! 所以,我的
我一整天都在挣扎。我的预输入搜索表达式与远程 json 数据完美配合。但是当我尝试使用相同的 json 数据作为预取数据时,建议为空。点击第一个标志后,我收到预定义消息“无法找到任何内容...”,结果
我正在制作一个模拟 NHL 选秀彩票的程序,其中屏幕右侧应该有一个 JTextField,并且在左侧绘制弹跳的选秀球。我创建了一个名为 Ball 的类,它实现了 Runnable,并在我的主 Draf
这个问题已经有答案了: How can I calculate a time span in Java and format the output? (18 个回答) 已关闭 9 年前。 这是我的代码
我有一个 ASP.NET Web API 应用程序在我的本地 IIS 实例上运行。 Web 应用程序配置有 CORS。我调用的 Web API 方法类似于: [POST("/API/{foo}/{ba
我将用户输入的时间和日期作为: DatePicker dp = (DatePicker) findViewById(R.id.datePicker); TimePicker tp = (TimePic
放宽“邻居”的标准是否足够,或者是否有其他标准行动可以采取? 最佳答案 如果所有相邻解决方案都是 Tabu,则听起来您的 Tabu 列表的大小太长或您的释放策略太严格。一个好的 Tabu 列表长度是
我正在阅读来自 cppreference 的代码示例: #include #include #include #include template void print_queue(T& q)
我快疯了,我试图理解工具提示的行为,但没有成功。 1. 第一个问题是当我尝试通过插件(按钮 1)在点击事件中使用它时 -> 如果您转到 Fiddle,您会在“内容”内看到该函数' 每次点击都会调用该属
我在功能组件中有以下代码: const [ folder, setFolder ] = useState([]); const folderData = useContext(FolderContex
我在使用预签名网址和 AFNetworking 3.0 从 S3 获取图像时遇到问题。我可以使用 NSMutableURLRequest 和 NSURLSession 获取图像,但是当我使用 AFHT
我正在使用 Oracle ojdbc 12 和 Java 8 处理 Oracle UCP 管理器的问题。当 UCP 池启动失败时,我希望关闭它创建的连接。 当池初始化期间遇到 ORA-02391:超过
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 9 年前。 Improve
引用这个plunker: https://plnkr.co/edit/GWsbdDWVvBYNMqyxzlLY?p=preview 我在 styles.css 文件和 src/app.ts 文件中指定
为什么我的条形这么细?我尝试将宽度设置为 1,它们变得非常厚。我不知道还能尝试什么。默认厚度为 0.8,这是应该的样子吗? import matplotlib.pyplot as plt import
当我编写时,查询按预期执行: SELECT id, day2.count - day1.count AS diff FROM day1 NATURAL JOIN day2; 但我真正想要的是右连接。当
我有以下时间数据: 0 08/01/16 13:07:46,335437 1 18/02/16 08:40:40,565575 2 14/01/16 22:2
一些背景知识 -我的 NodeJS 服务器在端口 3001 上运行,我的 React 应用程序在端口 3000 上运行。我在 React 应用程序 package.json 中设置了一个代理来代理对端
我面临着一个愚蠢的问题。我试图在我的 Angular 应用程序中延迟加载我的图像,我已经尝试过这个2: 但是他们都设置了 src attr 而不是 data-src,我在这里遗漏了什么吗?保留 d
我是一名优秀的程序员,十分优秀!