九维我操你爹
苹果测试工程师的日常
#北京を卒業しよう 片付けをしていて、思い出の物やすっかり忘れていた物が出てくると、つい見入っちゃう——こういうの、皆さんもよく分かるよね。 いま、家にある日本語関連の本を全部整理し終わったところなんだけど、ここまで支えてくれた本たちには「ありがとう」と言いたい(半分以上は積読本だけどな)。 ……あっ、昔の試験用紙や練習帳も見つけた。パラパラめくってみたら、思わず笑っちゃった。ふふふ。 この8年間の重さ、そして自分の成長を、改めて感じられた。
#北京倒计时
在收拾房间时,总会忍不住地沉浸在自己翻出来的旧物中,这一点大家应该都深有体会吧。
我现在刚刚整理完家里所有和日语学习相关的书,想对所有陪伴我至今的书说一声谢谢(虽然里面有一半多的书我到今天连封皮都没拆开🤫)。

……哦,里面还夹了好多过去的试卷和练习册。稍微翻来看了下,忍不住笑了出来。
过去八年的时光就这样部分以物理的形式呈现在我的眼前,我会带着它们去往下一个目的地——这是很自然的事,毕竟人都是要带着过去的成长继续前进的。
#北京を卒業しよう
片付けをしていて、思い出の物やすっかり忘れていた物が出てくると、つい見入っちゃう——こういうの、皆さんもよく分かるよね。
いま、家にある日本語関連の本を全部整理し終わったところなんだけど、ここまで支えてくれた本たちには「ありがとう」と言いたい(半分以上は積読本だけどな)。

……あっ、昔の試験用紙や練習帳も見つけた。パラパラめくってみたら、思わず笑っちゃった。ふふふ。
この8年間の重さ、そして自分の成長を、改めて感じられた。
知能がなさすぎにも限度ってあるよね

我:一个半小时后叫我起床(现在时刻下午一点)
苹果智障:好的,已经定好了下午一点半的闹钟
昨晚上在淘宝下单了轻洗到家的洗鞋服务。这个好像要他们客服处理订单以后才能预约上门取件的时间。所以现在单纯只是付了钱,连服务资格都还没生效,然后早上就接到了下面这通电话:

(陌生来电):你好,轻洗到家的,有需要保洁服务的吗?
:没有没有没有,我没有说想收到营销电话啊
(陌生来电):……
(机械):请您对我本次的服务做出评价,非常满意请按1……不满意请按3
:3
(机械):请您对我本次的服务做出评价,非常满意请按1……不满意请按3
:3
(机械):请您对我本次的服务做出评价,非常满意请按1……不满意请按3
:3
(电话被挂断了)

这还没开始服务就把好感败光了啊?不仅骚扰用户,简直就是不要脸啊😅
梓瑶在上周分享的 rust x SIGPIPE 的 issue 很有意思: https://t.me/ziyao233channel/3879
issue: https://github.com/rust-lang/rust/issues/62569

这里涉及了命令行软件和服务端软件的一些默认实践,我翻了一下几年前的笔记恢复了记忆。

服务端软件(socket 网络编程)通过 write (writev/sendto/sendmsg/sendmmsg) syscall 发送 tcp 流量,这里有个几乎无法避免的情况是,进程正在 write(sock),对端的 tcp reset 飞过来了,内核会抛出 SIGPIPE 信号通知进程这个 socket 不可写。

这个行为对于服务端软件是完全有害且多余。
- 说有害是因为 SIGPIPE 信号的默认处理是崩掉进程,然而 socket 收到 tcp reset 本来就是预期之内的情况,所以必须忽视 SIGPIPE。
- 说多余是因为忽视 SIGPIPE 之后,write syscall 返回 EPIPE 错误码,进程不可能错过这个报错,“正在给一个已经收到 tcp reset 的 socket 写数据” 的这个信息量没有得到任何丢失,反而由于同步化的 EPIPE 返回简化了信号处理(否则 pthread_sigmask + sigtimedwait 是有多想不开)

因此写网络程序直接 ignore SIGPIPE 百利无害,此事在 Unix Network Programming 中亦有记载,UNP 还是太权威了[1]

既然如此那为何要设计 SIGPIPE,全部用 EPIPE 错误码不就好了?答:unix 历史遗留 https://stackoverflow.com/questions/8369506/why-does-sigpipe-exist
这里带出了 SIGPIPE 的(几乎唯一?)需要抛出的场景,考虑命令行:
$ (echo 1; sleep 1; echo 2) | head -1
1
~ $ echo "${PIPESTATUS[@]}"
141 0


管道下游的 head -1 读到第一个 echo 1 的输出就退出进程了,关闭了 pipe_r,导致 pipe_w 不可写,上游的 echo 2 再 write(pipe_w) 的时候会遭遇 SIGPIPE 中止进程。
古典的 unix 命令行要求此时在 retval 里反映信号,141 == 128 + SIGPIPE(13)。

这个要求导致我们不能无脑 ignore SIGPIPE,否则看起来有点业余。(当然可以在命令行软件里看到 EPIPE 再手动 raise SIGPIPE / return 141

所以 rust 目前默认 ignore SIGPIPE 就常常会使 rust 编写的命令行工具在本应该返回 141 return code 时候返回 0(again,这是可以仔细处理好的:在 EPIPE 时 return 141

如果去看下 go 是怎么处理的,会发现它(貌似)更智慧一点:
A write to a broken pipe on file descriptors 1 or 2 (standard output or standard error) will cause the program to exit with a SIGPIPE signal. A write to a broken pipe on some other file descriptor will take no action on the SIGPIPE signal, and the write will fail with a syscall.EPIPE error.

https://pkg.go.dev/os/signal#hdr-SIGPIPE

更能照顾到绝大多数场景。

不过在 gdb 调试 go 进程时,由于 SIGPIPE 没有被 ignore,会触发 ptrace 的 signal-delivery-stop,很烦,但都是非常细微的 debugger 细节,正常人类不用管。。。

[1] https://flylib.com/books/en/3.225.1.83/1/

(再不分享点技术内容就要沦陷为飞升为男同交友频道了)
Back to Top