facts on drugs

Unix domain socket的抽象命名空间

摘自man unix

* abstract: an abstract socket address is distinguished by the fact that sun_path[0] is a null byte (‘\0′). The socket’s address in
this namespace is given by the additional bytes in sun_path that are covered by the specified length of the address structure. (Null
bytes in the name have no special significance.) The name has no connection with filesystem pathnames. When the address of an
abstract socket is returned by getsockname(2), getpeername(2), and accept(2), the returned addrlen is greater than sizeof(sa_family_t)
(i.e., greater than 2), and the name of the socket is contained in the first (addrlen – sizeof(sa_family_t)) bytes of sun_path. The
abstract socket namespace is a nonportable Linux extension.

lsof的结果里,带 @ 符号的套接字地址就是这种抽象命名空间的套接字,例如systemd所使用的一个套接字:

systemd 1 root 7u unix 0xffff8800b70cc000 0t0 3102 @/org/freedesktop/systemd1/notify

而这种是普通的Unix domain socket:

systemd 1 root 9u unix 0xffff8800b70cc340 0t0 3103 /run/systemd/private

抽象命名空间的 Unix domain socket 不会在文件系统生成一个 socket 文件。服务器端关闭以后,也会直接消失,不再需要一个 unlink 操作。

标签:

一个C++模板的问题

这其实是很早以前遇到的问题,但前几天因为别的原因讨论问题的提到了,把它写出来。

这个例子其实很简单:

#include <algorithm>
#include <cmath>
#include <cstdio>

using namespace std;

int main() {
        long long x = 9123456789123456789;

        long long y = abs(x);
        long long z = abs<long long>(x);

        printf("%lld\n", x);
        printf("%lld\n", y);
        printf("%lld\n", z);
        return 0;
}

使用 g++ 编译后,运行结果如下:

9123456789123456789
9123456789123456789
9123456789123457024

看输出的结果,x == y,这符合预期。但是 z 的值很莫名其妙地相差了两百多。

原因其实也不复杂,<cstdlib> 定义整数的 abs。它不是用模板定义的,而是重载了几种整数类型: abs(long), abs(long long)……

<cmath> 里定义了这样一个很坑的模板:

  template<typename _Tp>
    inline _GLIBCXX_CONSTEXPR
    typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value,
                                    double>::__type
    abs(_Tp __x)
    { return __builtin_fabs(__x); }

所以 abs(x) 会调用 <cstdlib> 里的 abs(long long),结果正确。
abs<long long>(x) 会调用 <cmath> 里的那个,会转成浮点。

在水木上经过分析后,结论貌似是:这个 abs 模板按 C++ 标准规定是不存在的,libstdc++ 作者自作聪明。

标签:

ADB解锁Android

Nexus 4 的电源键太烂了,已经换过一次。为了避免再次更换,现在尽可能少用电源键。

锁屏好办,在屏幕上放个 “一键锁屏” 就好,这样的应用太多。

解锁就有点麻烦,那些所谓 “音量键解锁” 基本都没法用,特别是在没有 root 的设备上。最后决定用 ADB 来解决这个问题:

adb shell input keyevent KEYCODE_POWER

把它写进一个脚本里。这样至少在机器插在电脑上时,可以完全避免使用电源键了。

标签: ,

curl_multi_wait 很坑

curl_multi_wait 的原型是这样:

CURLMcode curl_multi_wait(
         CURLM *multi_handle,
         struct curl_waitfd extra_fds[],
         unsigned int extra_nfds,
         int timeout_ms,
         int *numfds);

其中 curl_waitfd 结构体类似 struct poll:

struct curl_waitfd {
  curl_socket_t fd;
  short events;
  short revents; }; 

extra_fds 参数是没有带 const 的,然而这个函数是不修改 extra_fds[i].revents 的值的。其实这是举手之劳,并且非常有用,但它没有这样做。

标签: ,

很多人才

第二条好吧

尝试 X32 ABI

x32 ABI 是 x86-64 ABI 的一个变种,在长模式下运行,但使用 32 位指针 (当然也就限制了单个进程的地址空间不超过 4GiB)。今天心血来潮想试一下,才发现要让它跑起来还真费劲……

  • 早就注意到了机器上装的 GCC 4.7 和 4.8 (trunk) 能生成 x32 目标文件,但是我没有 x32 版本的 glibc。要在我的 Gentoo 上装它,需要先将 GCC 4.7 设为默认编译器——这太危险了。(Gentoo Bugzilla 上面现在还有很多 “*** fails to build with gcc-4.7″ 的未解决问题,我可以在虚拟机里面试新东西,但是主系统要足够稳定。)
  • 想起 Gentoo 曾经发布过一个 x32 Relese Candidate,决定在 VirtualBox 里面装它。以前也装过好多次 Gentoo 系统,基本上不会有什么大问题,但这一次,我发现没办法 chroot 到新系统里面去完成安装,因为我所有的 LiveCD 都太老了,支持不了 x32。
    • 最新的 Gentoo LiveCD 用的内核是 3.2,而 x32 支持直到 3.4 才并入内核主线。
    • 这时想起了 Arch Linux 这个以软件新为特点 (之一) 的发行版,下载了一个它的 ISO。果然,内核版本是对的 (3.4),但是在试图 chroot 到 x32 环境下时,总是段错误。一检查才发现,内核是用 CONFIG_X32=OFF 编译的!
    • 于是试了 Ubuntu 12.10 Alpha 3 LiveCD,它似乎有 X32 支持,但是只给了一个 busybox shell,没有 LVM 支持,懒得重新布局分区了。
  • 好吧。我应该先装一个普通 amd64 版本,然后从那里面再装 x32 吗?或者自己编译内核、做一个 ISO?算了,没那么多时间浪费。最后,干脆在主系统里弄一个 x32 的 chroot 环境 算了。

大概 AMD 在设计 AMD64 (x86-64) 的时候就预计到了 x32 ABI 吧,要不然怎么解释长模式下支持 32 位寻址 (0×67 前缀) 呢?

标签: