Vala

なんか GTK の UI を作ろうかと思って、Valaで書くのがよさそうな気がしたのでValaというのを触ってみたが、なんか思ってたよりよかったな。

まあRustが打倒C++できそうな今の時代に、わざわざマイナーなValaを使ってもあんま良いことないと思うけど、まあ良かったと思う点を書いておく

リファレンスカウンタと文字列があってコンパイルがはやい

個人的には、プログラミング言語の機能って、C99 に自明な場合だけでもいいのでうまくやってくれるリファレンスカウンタと、文字列のconcatが簡単にできるぐらいで十分だと思ってたのだけど、大体そのぐらいの機能になっててよかった。

リファレンスカウンタやunownedは、Rustの所有権と比べたら雰囲気ぐらいの機能しかなくて、安全でないパターンが書けてしまうのはたしかにそうなんだけど、実際プログラム書いてると所有権は雰囲気ぐらいでなんとかするふんわりしたダーティなプログラム書きたくなることってないですか?まあそういうのはあとから自分を苦しめるだけだからあんまよくないけど。

あとC++とかRustってコンパイル遅くていやになることあるけど、Valaはまあそんなにコンパイル遅くない

typeinfo の API が決まってる

静的型チェックがある言語で、これ実現してるプログラミング言語ってあんま無くない?

中身はGLibのgobjectではあるけど、これのおかげで、Vala で書いたオブジェクトをPythonから呼び出すみたいなのはコード書かなくても実現できる。これは、他のgir binding (glibmmとか、gtk-rs) にはない機能のはず。

Makefile

all: test_shared-0.1.typelib

test_shared-0.1.typelib: libtest_shared-0.1.so
	g-ir-compiler --shared-library=$< --output=$@ test_shared-0.1.gir

libtest_shared-0.1.so: gir.vala
	valac --gir test_shared-0.1.gir --library=test_shared $< -X -fPIC -X -shared -o $@

gir.vala

namespace TestNS {

public class TestCLS : Object{
  public int y {get; set;}
}

}

run.py

import gi
gi.require_version('test_shared', '0.1')
from gi.repository import test_shared

v = test_shared.TestCLS.new()

v.set_y(10)
print(v.get_y())

Cからbinding作るのがエモい

なんか色々楽しい機能が付いていて色々なC関数をバインディング用のコード書かなくてもValaっぽく書けるようになるのがエモくていい。

https://wiki.libsdl.org/SDL_AddTimer

こういう、コールバックに、void *として汎用オブジェクトを渡すようなのを、なんかうまく書ける。

class Obj {
  public uint32 timer_callback(uint32 interval) {
    stdout.printf("callback : %p\n", this);
    return 0;
  }
}

public int main(string [] args) {
  SDL.init();

  var obj = new Obj();
  stdout.printf("init : %p\n", obj);

  SDL.Timer(1000, obj.timer_callback);

  SDL.Timer.delay(2000);

  return 0;
}

obj と紐付いたtimer_callbackが呼ばれるようになっている。これは、

static guint32
_obj_timer_callback_sdl_timercallback (guint32 interval,
                                       gpointer self)
{
	guint32 result;
	result = obj_timer_callback ((Obj*) self, interval);
	return result;
}

gint
_vala_main (gchar** args,
            gint args_length1)
{
	Obj* obj = NULL;
	Obj* _tmp0_;
	FILE* _tmp1_;
	SDL_TimerID _tmp2_;
	gint result = 0;
	SDL_Init ((guint32) SDL_INIT_EVERYTHING);
	_tmp0_ = obj_new ();
	obj = _tmp0_;
	_tmp1_ = stdout;
	fprintf (_tmp1_, "init : %p\n", obj);
	_tmp2_ = SDL_AddTimer ((guint32) 1000, _obj_timer_callback_sdl_timercallback, obj);
	SDL_Delay ((guint32) 2000);
	result = 0;
	_obj_unref0 (obj);
	return result;
}

このような形にコンパイルされる。SDL_AddTimer の void * param を、なんかいい感じにうまいことやってくれてるというのがわかるだろうか。

これは、どうなってるかというと、コールバックの際にそのコールバックと紐付けられる this の引数の位置を指定できるようになっている。

https://github.com/GNOME/vala/blob/4c63d52fb24b2b9847c5615c38f8e9f707bddd65/vapi/sdl2.vapi#L4439

delegate_target_pos がそれ。

他にも、Cから配列を返すときに、その配列の長さを格納するポインタが何番目の引数かを指定するみたいなことができる。

こういう細かい気配りがエモくていい。

まとめ

まあなんかそういうあたりが好きだった。

GTKで何か書くときは、Cで書くより圧倒的に楽だし、glibmm とか gtk-rs で書くよりコンパイル時間短くできるので、嫌いでなければ使ってみるのも楽しいのではないかと思います。

swayからi3へ移行しました

すいません。


これはswayに問題があったわけではなくて、うちのRADEONをつけるとマザボごと死ぬので諦めた次第であります。(電源ボタンもきかなくなる)


正直Ryzenってすぐ不安定環境にならないですか…私は電圧オフセット+0.250V 追加して運用してる。これやらないとLinuxだとsoft lockupして死ぬ。これはRADEONでなくてもなる。

https://w0.hatenablog.com/entry/20170621/1497988036
この頃は出ないと書いてあるな。なんかこのあとBIOSアプデトしたら死ぬようになって、それ以降マザボRyzenもメモリも更新したけど安定したときない。


見てる不安定現象

  • Linux で soft lockup する → これは電圧盛れば解決する
  • 再起動に失敗する → これは解決したことない
  • 突然マザボごと死ぬ → これは手元のRADEON付けたときだけ発生する

どれも電源っぽいし実は電源変えたら改善したりしてな。
電源は交換したことない。(とはいえ根本の電源がCPU速度の電力上下に影響するものなのか?)

いやRyzenBIOS更新やるからよくないんだよな。Intelが安定してる理由のひとつに、マザボとCPUが常にセットになってるのもある気がする。
基本的に次の世代のCPUが出たあとにBIOS更新すると安定度下がってる気がする。多分前世代のファームウェアはテスト控えてるとかなんかそんな感じなんじゃないかな…
ファームウェア安定してる気がしたら更新しないようにしよう(無理)


いやさすがに+0.250は盛りすぎな気がする。+0.0250とかでよかったかも→試したら速攻死んだ。多分+0.0500ぐらいでよかったはず。

memo: 0.0875 まで上げた

追記: 電源も変えたけど変わらんかったです

pidfd_open

pidfd_open

pkill 打つたびに、「これpid再利用されたら地球が爆発するよな…」とか思っていたのだけど、今はpidfd_openがあるので助かった。

#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <poll.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>

static int  pidfd_send_signal(int pidfd, int  sig, siginfo_t *info,
                              unsigned int flags) {
    return syscall(__NR_pidfd_send_signal, pidfd, sig, info,
                   flags);
}


static int
pidfd_open(pid_t pid, unsigned int flags)
{
  return syscall(__NR_pidfd_open, pid, flags);
}

int
main(int argc, char **argv)
{
    int child;
    int use_pidfd = 1;
    if (argc > 1) {
        use_pidfd = atoi(argv[1]);
    }

    if (use_pidfd) {
        puts("use pidfd_send_signal");
    } else {
        puts("use kill");
    }

    if ((child=fork()) == 0) {
        exit(0);
    } else {
        printf("child = %d\n", child);
        int status;
        int pidfd = pidfd_open(child, 0);
        int r = pidfd_send_signal(pidfd, SIGUSR1, NULL, 0);
        if (r < 0) {
            /* プロセスが生きてるあいだはpidfd_send_signalが届く */
            perror("pidfd_send_signal");
            return 1;
        }
        char path[1024];
        sprintf(path, "/proc/%d", child);
        int pidfd2 = open(path, O_RDONLY);
        r = pidfd_send_signal(pidfd2, SIGUSR1, NULL, 0);
        if (r < 0) {
            /* /proc/PID も pidfd として使える */
            perror("pidfd_send_signal");
            return 1;
        }
        int fd2 = openat(pidfd2, "cmdline", O_RDONLY);
        if (fd2 < 0) {
            /* プロセスが生きてる間は openat で cmdline が開ける */
            perror("cmdline");
            return 1;
        }
        close(fd2);

        wait(&status);

        for (int i=0; i<1000000; i++) {
            int child2;
            if ((child2 = fork()) == 0) {
                int self = getpid();
                if (self == child) {
                    sleep(10);
                }
                exit(0);
            } else {
                if (child2 == child) {
                    if (use_pidfd) {
                        int r = pidfd_send_signal(pidfd, SIGUSR1, NULL, 0);
                        perror("send signal");

                        int fd = openat(pidfd2, "cmdline", O_RDONLY);
                        perror("openat");
                        close(fd);

                        exit(0);
                    } else {
                        int r = kill(child, SIGUSR1);
                        perror("kill");

                        sprintf(path, "/proc/%d/cmdline", child);

                        int fd = open(path, O_RDONLY);
                        perror("open");
                        close(fd);
                        exit(0);
                    }
                }

                wait(&status);
            }
        }
    }
}

この実験プログラムはpid一周するのを期待しているけど、今のLinuxデフォルト値だとpid一周するまで時間かかるので、pid最大値下げて実験するのをおすすめする。

 $ echo 65536 > /proc/sys/kernel/pid_max

最初に子プロセスを立ち上げて、即終了する。このpidに対して、シグナルを送った場合、どのプロセスにもシグナルが届いてほしくない。

しかし、シグナル送るまでに大量のforkを実行すると、pidが一周して、既存の kill(2) だと、新しくできたプロセスにシグナルを送ってしまう。

そこで、pidfdを使う。

pidfd_open で開いた FD は、そのプロセスがいなくなるとどのプロセスも指さなくなる。pid が一周したあと、pidfd に対してシグナルを送っても、意図しないプロセスには届かない。

$ ./a.out 0  # killを使う
use kill
child = 7416
kill: Success # PID一周するとシグナルが送れてしまう (Successと出てるが、ここは失敗してほしい)
open: Success # /proc/PID/cmdline も開ける


$ ./a.out 1  # pidfd_send_signalを使う
use pidfd_send_signal
child = 7418
send signal: No such process # PID 一周するとシグナル送れない
openat: No such process # /proc/PID/cmdine も開けない


まあでも今のpkillはstraceで見たけどそういう実装にはなってないっぽい?

/proc/PID を開いても、pidfd は取得できる。これで、安全なpkillができるはず。

i3からswayへ移行し、gccemacs + pgtk にした

もう戻らないでいけるやろ。

Xorg はマルチディスプレイのときにディスプレイごとにスケール変えるのができなくて微妙なことをやってたがもう考えなくていい。

  • emacs を pgtk にしたので、Xwaylandも無くてもいける。Arch なら emacs-native-comp-git-enhanced 入れれば一発で gccemacs + pgtk にできる。
  • 環境変数は、.pam_environmentで変えるのがやりたいことだと思うのでそうしている。(どこから何でログインしても環境変数統一したい。pamを通らないことはないやろ)
  • xrandr のかわりは、sway の config に書く
  • ctrl:swapcaps も sway の config に書く
  • Firefox は何故かデフォルトXになるので、 MOZ_ENABLE_WAYLAND=1 する
  • NVIDIA GPUは…諦めよう!

caps を ctrl にするには↓ を~/.config/sway/configに書く

input "type:keyboard" {
           xkb_options caps:ctrl_modifier
}

ディスプレイの配置も ~/.config/sway/config に書く

output DVI-I-1 position 0,0 res 1920x1200 scale 1
output DP-1 position 1920,0 res 3840x2160 scale 1.5

gccemacsどうなんですか → ごめんあんま違いわからん。違いがわからない程度に困ってはない

無駄

オリンピックロゴも、競技場ザハ案も、会長も、国民からのクレームでやりなおし(いや私は国民だけどどうでもいいと思ってるのでクレーム出してない。これは必要以上に主語が大きくなっている。いわゆるビッグシュゴだ)。現代民主主義の象徴やな。

どれもまあロクでもない経緯があるように見えるけど、新聞しかなかった時代なら誰もロクでもないと知ることも無く穏便に終わってただろうな。

(いやでもザハ案は今の競技場の写真と比べたらクソカッコよく見えるからやっぱやるべきだったのでは…)

MMTとかみたいな、「国の予算はもっと無駄遣いすべき!」みたいな説を信じてる人は、オリンピックとかいう究極の無駄について考えてみるべきだと思いますね。国の予算が増えればオリンピックみたいな無駄が実施される、という現象が発生する。

よく「財務省が諸悪の根源」みたいな言われかたするけど、「財務省がちゃんと財布管理して、オリンピックとかいう無駄を止めてればよかった」みたいな考えかたもできるわけ。

「オリンピックみたいなのではなく、もっと○○に無駄遣いしろ!」という考えをするのも危険でしょ。よく知りもしない他人の仕事と自分の仕事のどちらが無駄かどうかを比較するのなんて無理だし、できると思ってる奴は危険な思想の持ち主だとわたしは思う。



国レベルで見ると、予算というのは、いくらでもやりようのある現金ではなくて、その背後にある実際のリソースに律速するわけ。


オリンピックで考えると、競技場作り直すために使われたリソースが無駄遣いされてなければ、もっとなんか地方の壊れそうな橋やトンネルを修復するのに使えたかもしれない。

これは、現象としては、

  • 建設会社にオリンピック関連の補助付きの仕事が行って、建設会社は潤う。建設会社のリソースは需要が上がるので値段があがる
  • 建設の値段が上がるので、地方の予算に余裕の無い自治体は橋やトンネルを修復したりできなくなる

という形で表面化する。(まあ競技場建てるリソースと橋を修復リソースがどれだけ重複してるかは私は知らんので雑な議論だけど)


オリンピックが無ければ、地方の橋やトンネルは修復されたかもしれない。(ただ、その場合は建設会社が安い仕事を請け負ってるわけで、建設会社としてはあまり嬉しくはない)


そういうふうに考えれば、「何か健全ではないことが起きてるかも?」という気がしてこないだろうか。


結局MMTみたいな「国の予算もっと増やせ」という考えかたは「実際のリソース配分を判断する人が一部の権力者に偏ってしまう」という形で表面化すると思ってる。

オリンピックをやるかどうかの決定において、大半の国民の意思が入る余地なんてなかったでしょ。それに比べたら、「地方の壊れそうな橋をどういう優先度付けて修復していくか」という判断のほうが、自治体レベルの話になってるので、まだ住民の判断が入ってるのではないでしょうか。


もちろん、オリンピックだって、国威発揚になってみんなが元気になれば、プラスになるかもしれない可能性はある。ただ、僕が健全ではないと思うのは、「やるかどうかの判断に関わっている人間が少ないのでは?」という点だ。


現代の社会の複雑さでは、「一部の賢い人間が全てを判断する」のはもう難しくて、たとえ効率悪くても、それぞれ個人個人がなんかうまいこと判断していかないといけない。
現代の民主主義はひとりひとりがよく考えて判断する、というのを前提に動いてるでしょ。「国の予算もっと増やせ」というのは、その方向に反してると、思いますね。


まあ、これは程度問題ではあって、「雇用を守る」みたいな話になってくる。まあなにごともホドホド…ホドホドがいいデスネ。MMTはホドホドではないと思っている。

献血

2回目に行った。


1回目行った理由は、輸血が必要だという話をなんかで聞いたときに、「これ保存されてる血液量足りない場合助からないんだろうか」とか思ってしまって、「私は献血なんか行ったことないのに、保存されてる血液量の心配をしてフリーライダーだな…」とか考えて、自分がみんなの善意にフリーライドしてるという事実が辛かったので行ってみることにした。


1回行くとクセになったので今日も行った。どちらも全血 400ml。これは、成分献血はいつも予約埋まっていて、3週間前ぐらいから予約入れないといけないのだけど、私は3週間前とかから予約立てるの不可能な人間なので…
全血は土日でも2日前くらいには予定取れることが多い。(私が最初に行ったときは当日飛び込みだった)


http://nano.flop.jp/log2/200711.html#2007-11-05 私は健康診断の採血で貧血になるくらい血が苦手なのだけど(正確には貧血でなくて迷走神経反射)、まあ行けてる。

同じような人向けに書いておくと、献血時には迷走神経反射起こらないように、だいぶ気が使われていて、

  • 事前に水分をとれ
  • 事後にも水分をとれ
  • ちゃんと寝てからこい
  • 急に立ち上がるな
  • 少しでもフラっとしたら座って休憩しろ

みたいな注意を3回くらいされる。https://www.bs.jrc.or.jp/csk/hiroshima/2017/12/vvr.html 実績としては、1%の人が迷走神経反射にあうっぽい。

私は「血が出てる」みたいな意識するとクラっとしそうになるので、あんま何も考えないようにしながら血を抜いている。


献血に行くと意識が高まるので意識高いついでに書いておくと、今は、感染症対策の影響で、集団献血が減っていて、在庫量がかなり厳しくなっているらしいので、興味ある人は行ってみような。


これは、あくまで私個人の考えではあるけど、今は「医療従事者に感謝を」みたいなことを言われることが多いけど、なんらかの形で感謝をしたいと思ってる人は、献血によってその感謝の気持ちを表現することができると思うんだよね。献血が増えれば助かる医療従事者はそれなりにいると思う。