调试X11程序时如何避免SIGPIPE(由于超时?)?

时间:2019-06-20 13:03:03

标签: c++ qt x11 sigpipe

有时候,当我在X11上调试我的Qt程序时,我需要在程序创建窗口(QWidget)时有一个断点,但是还没有显示窗口。在这种情况下,当我在一段时间后从此断点恢复程序时,程序将得到SIGPIPE。当程序在显示窗口之前做一些事情时,也会发生这种情况,Valgrind将其降低到如此低的速度,以至于X11再次超时。至少似乎与某种超时有关。

我设法制作了一个小型测试用例,无需使用调试器或Valgrind即可完全重现问题:

#include <QThread>
#include <QWidget>
#include <QApplication>

int main(int argc, char** argv)
{
    QApplication app(argc, argv);
    QWidget widget;
    QThread::currentThread()->sleep(60);
    widget.show();
    return app.exec();
}

此程序获取SIGPIPE时,其堆栈跟踪如下所示:

Thread 1 "test" received signal SIGPIPE, Broken pipe.
0x00007ffff6385187 in __GI___libc_write (fd=6, buf=buf@entry=0x5555557be990, nbytes=nbytes@entry=80) at ../sysdeps/unix/sysv/linux/write.c:27
27      ../sysdeps/unix/sysv/linux/write.c: No such file or directory.
(gdb) bt
#0  0x00007ffff6385187 in __GI___libc_write (fd=6, buf=buf@entry=0x5555557be990, nbytes=nbytes@entry=80) at ../sysdeps/unix/sysv/linux/write.c:27
#1  0x00007fffed6e5cd8 in _IceTransSocketWrite (ciptr=0x5555557be4b0, buf=0x5555557be990 "\001\f\001", size=80) at /usr/include/X11/Xtrans/Xtranssock.c:2396
#2  0x00007fffed6ea558 in _IceWrite (iceConn=0x5555557c3d80, nbytes=<optimized out>, ptr=0x5555557be990 "\001\f\001") at ../../src/misc.c:350
#3  0x00007fffed6ea644 in IceFlush (iceConn=0x5555557c3d80) at ../../src/misc.c:78
#4  0x00007fffefa56c24 in sm_setProperty (name=0x5555557daa08 "Program", type=0x7fffefb0667a "ARRAY8", num_vals=1, vals=0x7fffffffccc0) at qxcbsessionmanager.cpp:123
#5  0x00007fffefa56ce8 in sm_setProperty (name="Program", value="/tmp/test/test") at qxcbsessionmanager.cpp:137
#6  0x00007fffefa57188 in sm_performSaveYourself (sm=0x5555557753e0) at qxcbsessionmanager.cpp:202
#7  0x00007fffefa56f93 in sm_saveYourselfCallback (smcConn=0x5555557bc9e0, clientData=0x5555557753e0, saveType=1, shutdown=0, interactStyle=0) at qxcbsessionmanager.cpp:180
#8  0x00007fffed8fdb28 in _SmcProcessMessage (iceConn=0x5555557c3d80, clientData=0x5555557bc9e0, opcode=<optimized out>, length=<optimized out>, swap=0, replyWait=<optimized out>, replyReadyRet=0x7fffffffd2d0) at ../../src/sm_process.c:241
#9  0x00007fffed6ee978 in IceProcessMessages (iceConn=0x5555557c3d80, replyWait=0x0, replyReadyRet=0x0) at ../../src/process.c:386
#10 0x00007fffefa57ae6 in QSmSocketReceiver::socketActivated (this=0x5555557be520) at qxcbsessionmanager.cpp:331
#11 0x00007fffefa58298 in QSmSocketReceiver::qt_static_metacall (_o=0x5555557be520, _c=QMetaObject::InvokeMetaMethod, _id=0, _a=0x7fffffffd4a0) at .moc/qxcbsessionmanager.moc:70
#12 0x00007ffff6f6521d in QMetaObject::activate (sender=0x5555557be450, signalOffset=3, local_signal_index=0, argv=0x7fffffffd4a0) at kernel/qobject.cpp:3795
#13 0x00007ffff6f649e6 in QMetaObject::activate (sender=0x5555557be450, m=0x7ffff733bda0 <QSocketNotifier::staticMetaObject>, local_signal_index=0, argv=0x7fffffffd4a0) at kernel/qobject.cpp:3648
#14 0x00007ffff6f72321 in QSocketNotifier::activated (this=0x5555557be450, _t1=6, _t2=...) at .moc/moc_qsocketnotifier.cpp:140
#15 0x00007ffff6f72081 in QSocketNotifier::event (this=0x5555557be450, e=0x7fffffffda20) at kernel/qsocketnotifier.cpp:266
#16 0x00007ffff74c1ce4 in QApplicationPrivate::notify_helper (this=0x5555557701d0, receiver=0x5555557be450, e=0x7fffffffda20) at kernel/qapplication.cpp:3736
#17 0x00007ffff74bf0a2 in QApplication::notify (this=0x7fffffffdc60, receiver=0x5555557be450, e=0x7fffffffda20) at kernel/qapplication.cpp:3093
#18 0x00007ffff6f1c919 in QCoreApplication::notifyInternal2 (receiver=0x5555557be450, event=0x7fffffffda20) at kernel/qcoreapplication.cpp:1060
#19 0x00007ffff6f1d316 in QCoreApplication::sendEvent (receiver=0x5555557be450, event=0x7fffffffda20) at kernel/qcoreapplication.cpp:1450
#20 0x00007ffff6fa5a27 in QEventDispatcherUNIXPrivate::activateSocketNotifiers (this=0x555555774f30) at kernel/qeventdispatcher_unix.cpp:304
#21 0x00007ffff6fa686e in QEventDispatcherUNIX::processEvents (this=0x7fffe4001460, flags=...) at kernel/qeventdispatcher_unix.cpp:509
#22 0x00007fffefa4715a in QXcbUnixEventDispatcher::processEvents (this=0x7fffe4001460, flags=...) at qxcbeventdispatcher.cpp:60
#23 0x00007ffff6f19169 in QEventLoop::processEvents (this=0x7fffffffdbd0, flags=...) at kernel/qeventloop.cpp:138
#24 0x00007ffff6f194a3 in QEventLoop::exec (this=0x7fffffffdbd0, flags=...) at kernel/qeventloop.cpp:225
#25 0x00007ffff6f1d15a in QCoreApplication::exec () at kernel/qcoreapplication.cpp:1363
#26 0x00007ffff584f1c4 in QGuiApplication::exec () at kernel/qguiapplication.cpp:1779
#27 0x00007ffff74be931 in QApplication::exec () at kernel/qapplication.cpp:2893
#28 0x0000555555554c34 in main (argc=1, argv=0x7fffffffdda8) at test.cpp:11

如果我忽略了此信号(例如,在GDB中为signal 0,那么我会收到错误消息

ICE default IO error handler doing an exit(), pid = 3850, errno = 32

仅执行类似sigaction的解决方法是行不通的。

我的问题是:如果这确实是X11超时,如何禁用或增加该超时?如果不是超时,那是什么,以及如何避免此SIGPIPE / ICE错误问题?

1 个答案:

答案 0 :(得分:1)

看来,如果我在创建public class WordAdapter extends RecyclerView.Adapter<WordAdapter.ViewHolder> { private List<Word> wordList; private OnNoteListener mOnNoteListener; public WordAdapter(List<Word> wordList, OnNoteListener onNoteListener) { this.wordList = wordList; this.mOnNoteListener = onNoteListener; } public WordAdapter(OnNoteListener onNoteListener) { this(new ArrayList<Word>(), onNoteListener); } public void addItems(List<Word> items) { wordList.addAll(items); notifyDataSetChanged(); } public void clear() { wordList.clear(); notifyDataSetChanged(); } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_items, viewGroup, false); return new ViewHolder(view, mOnNoteListener); } @Override public void onBindViewHolder(@NonNull ViewHolder viewholder, int position) { int resource = wordList.get(position).getImageResource(); String title = wordList.get(position).getTitle(); viewholder.setData(resource, title); } @Override public int getItemCount() { return wordList.size(); } static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { private ImageView imageView; private TextView title; private OnNoteListener onNoteListener; public ViewHolder(@NonNull View itemView, OnNoteListener onNoteListener) { super(itemView); imageView = itemView.findViewById(R.id.imageView); title = itemView.findViewById(R.id.word); this.onNoteListener = onNoteListener; itemView.setOnClickListener(this); } private void setData(int resource, String titleText) { imageView.setImageResource(resource); title.setText(titleText); } @Override public void onClick(View view) { onNoteListener.onNoteClick(getAdapterPosition()); } } public interface OnNoteListener { void onNoteClick(int position); } } 实例后立即调用QApplication::processEvents(),则QApplication不会发生。显然,Qt会以某种方式“确认”应用程序对X11的有效性,以响应某些事件,从而使应用程序尽可能慢,而不会受到致命的惩罚。

编辑后的示例代码如下:

SIGPIPE

我仍然不知道到底发生了什么,什么事件需要迅速的反应,以及是否可以延长超时时间,但是至少上述解决方法可以让我继续进行调试。