c++ - Tcl fileevent 在 64 位版本的 Tcl 上挂起

标签 c++ linux tcl 64-bit x11

我在 Linux 上使用 64 位 8.4.3 Tcl 非线程,我遇到了一个奇怪的行为。

我的 C++ 应用程序有一个计时器,它使用 XtAppProcessEvent 执行一些 Xt 处理程序。其中一个处理程序调用 Tcl_DoOneEvent

我有一个 Tcl 脚本,它打开一个空管道并将一个文件事件附加到打开的 channel 。

set jobId [open "| "]
fileevent $jobId readable

这会完成多次。一段时间后,当 channel 名称为 file35 时,该工具会挂起。使用 Tcl 库的调试版本。表明执行以下部分后readyMasks[0]一直为0:

// tclUnixNotfy.c:772
numFound = select(tsdPtr->numFdBits,
    (SELECT_MASK *) &tsdPtr->readyMasks[0],
    (SELECT_MASK *) &tsdPtr->readyMasks[MASK_SIZE],
    (SELECT_MASK *) &tsdPtr->readyMasks[2*MASK_SIZE], timeoutPtr);

输入检查掩码是 72 (1001000)。


这是奇怪的部分:

当我到达工具挂起的部分时,如果我打开一个新的 shell 选项卡,该工具将不再挂起并按预期继续执行。当打开一个新的 shell 选项卡时,readyMasks 变为 72。

该工具在 32 位时运行正常。我无法将发生的事情与 64 位联系起来。

我已经在 redhat 5、6 和 7 上试过了,没有任何区别。

最佳答案

所以,我想通了这个问题。

这个问题基本上是由于转移了一个 integer而不是 long .这在 Tcl 中是在 tclUnixChan.c 中完成的在计算需要在 tsdPtr->checkMasks 中修改的索引和位时:

index = fd/(NBBY*sizeof(fd_mask)); 
bit = 1 << (fd%(NBBY*sizeof(fd_mask)));

位线需要为1L <<而不是 1 << . fd_mask本身就是一个 long并在 sys/types.h 中定义.这只是问题的一部分。

sys/types.h也有在设置或清除 fd_masks 中的位时应使用的宏定义(FD_CLRFD_SETFD_ISSETFD_ZERO)。

此问题已在版本 8.4.9 中部分修复并在版本 8.4.20 中得到完全修复.

修复是通过使用 types.h 中定义的宏完成的而不是手动操作 fd_mask位。

版本 8.4.9 中引入的部分修复在tclUnixNotfy.c :

  1. 结构SelectMasks创建它使用 fd_set types.h 中定义的类型
  2. 线程特定数据 checkMasksreadyMasks字段从 fd_mask 更改为数组为 SelectMasks
  3. indexbit Tcl_CreateFileHandler 中使用的变量, Tcl_DeleteFileHandler , Tcl_WaitForEvent , NotifierThreadProc处理面具被移除和FD_CLR , FD_SET , FD_ISSET , FD_ZERO被改用了。
  4. Tcl_WaitForEvent分配 readyMaskscheckMasks而不是使用 memcpy打电话前 select
  5. 类型转换readyMasksSELECT_MASK *现在调用 select 时被删除并且 &运算符现在用于 SelectMasks fd_set 类型的结构元素直接。

修复的另一部分在版本 8.4.20 中引入在tclUnixChan.c :

  1. indexbit TclUnixWaitForFile 中使用的变量处理面具被移除和FD_CLR , FD_SET , FD_ISSET , FD_ZERO被改用了。
  2. fd_set使用类型而不是创建 fd_mask TclUnixWaitForFile 中的数组.
  3. SELECT_MASK * 蒙上面具现在调用 select 时被删除并且 &运算符现在用于创建的 fd_set直接变量。

我已经修补了当前版本的 8.4.38.4.9 中所做的更改为指导和 8.4.20因为我没有升级整个 Tcl 的灵 active 版本。


我关于为什么打开一个新的 shell 窗口使该工具起作用的理论:

由于在错误大小的容器中移动并使用 memcpy 导致内存损坏奇怪的长度3*MASK_SIZE , fd我最后指出是窗口管理相关的,因此为什么打开一个新的 shell 得到选择返回非零值,因为这些错误的数据 fd我指向的 channel 。

让我得出这个理论的是 strace输出以及 lsof输出:

strace挂起时的输出重复了以下部分:

poll([{fd=4, events=POLLIN}, {fd=5, events=POLLIN|POLLPRI|POLLRDNORM|POLLRDBAND}], 2, 0) = 0 (Timeout)
recvfrom(4, 0x80e21f4, 4096, 0, 0, 0)   = -1 EAGAIN (Resource temporarily unavailable)
recvfrom(4, 0x80e21f4, 4096, 0, 0, 0)   = -1 EAGAIN (Resource temporarily unavailable)
poll([{fd=4, events=POLLIN}, {fd=5, events=POLLIN|POLLPRI|POLLRDNORM|POLLRDBAND}], 2, 0) = 0 (Timeout)
recvfrom(6, 0x8380d64, 4096, 0, 0, 0)   = -1 EAGAIN (Resource temporarily unavailable)
select(36, [3 6], [], [], {0, 0})       = 0 (Timeout)
recvfrom(6, 0x8380d64, 4096, 0, 0, 0)   = -1 EAGAIN (Resource temporarily unavailable)
recvfrom(6, 0x8380d64, 4096, 0, 0, 0)   = -1 EAGAIN (Resource temporarily unavailable)
select(36, [3 6], [], [], {0, 0})       = 0 (Timeout)
recvfrom(6, 0x8380d64, 4096, 0, 0, 0)   = -1 EAGAIN (Resource temporarily unavailable)
poll([{fd=4, events=POLLIN}, {fd=5, events=POLLIN|POLLPRI|POLLRDNORM|POLLRDBAND}], 2, 0) = 0 (Timeout)
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigaction(SIGCHLD, NULL, {0x4c3cd70, [CHLD], SA_RESTORER|SA_RESTART|SA_SIGINFO, 0x37eec0f790}, 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0

strace当我打开一个新的 shell 选项卡时输出更改为:

poll([{fd=4, events=POLLIN}, {fd=5, events=POLLIN|POLLPRI|POLLRDNORM|POLLRDBAND}], 2, 0) = 1 ([{fd=4, revents=POLLIN}])
recvfrom(4, "X\1\366\371\264\300\7=\3\0\22\0\10\377\0\0\26\1\26\1\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096, 0, NULL, NULL) = 256
recvfrom(4, 0x80e21f4, 4096, 0, 0, 0)   = -1 EAGAIN (Resource temporarily unavailable)
recvfrom(4, 0x80e21f4, 4096, 0, 0, 0)   = -1 EAGAIN (Resource temporarily unavailable)
poll([{fd=4, events=POLLIN}, {fd=5, events=POLLIN|POLLPRI|POLLRDNORM|POLLRDBAND}], 2, 0) = 0 (Timeout)
recvfrom(6, "X\1\321/\264\300\7=\3\0\22\0\10\377\0\0\26\1\26\1\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096, 0, NULL, NULL) = 256
recvfrom(6, 0x8380d64, 4096, 0, 0, 0)   = -1 EAGAIN (Resource temporarily unavailable)
select(36, [3 6], [], [], {0, 0})       = 1 (in [3], left {0, 0})
recvfrom(6, 0x8380d64, 4096, 0, 0, 0)   = -1 EAGAIN (Resource temporarily unavailable)
read(35, "", 4096)                      = 0
close(35)                               = 0

lsof输出显示 channel 的以下内容 46 :

myexec 13626 aymansalah    4u  IPv4 1607796326       0t0        TCP rhe6x64:38787->nx-svr:7016 (ESTABLISHED)
myexec 13626 aymansalah    6u  IPv4 1607837231       0t0        TCP rhe6x64:38788->nx-svr:7016 (ESTABLISHED)

channel 46是将我的机器连接到 NX 服务器的 channel 。


引用资料:

关于c++ - Tcl fileevent 在 64 位版本的 Tcl 上挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56416818/

相关文章:

c++ - 在 VS2015 C++ 中打印我的用户名

linux - 检查和修改期望脚本中变量的格式

c++ - 使用 boost C++ 单元测试套件测试非 fatal error 消息

c++ - 在 Win32 桌面应用程序上创建按钮时出错

c++ - 这是初始化我的图书馆的合理方式吗?

linux - 让 Expect 进行交互直到程序终止

linux - 使用外部 redis 服务器测试 tcl 脚本

linux - 如何在 Bash 脚本中显示密码最小长度的输出

c++ - 如何向静态库添加分析编译?

java.net.ConnectException : Connection refused in Hadoop while using shell commands