Kindle Cloud Readerは、なんか読んでると勝手にログアウトされるし、なんかページのロードに失敗すると、2日後ぐらいまでそのページ読めなくなったりするんだよね。

でもレコメンデーションは圧倒的にAmazonがよくて、dmmのレコメンデーションは単に距離が近いだけの本が並んでいて、これであんま何かが見つかることがないのだけど、Amazonのおすすめはリンク辿っていくとなんか読みたくなるものが見つかる場合がある。

最近はAmazonで買ってないが、それでもおすすめはAmazonのほうがいい。Amazonで探してdmmで買う。

電子書籍は買ってるわけではないんだよなぁ…使用許諾を得てるだけやぞ。(どうでもいい)

最近よかった漫画

(PCで読むときはKindle Cloud Readerがクソすぎてもう漫画読むときKindle使ってないのでリンク先はdmmです)

ブルーロック
https://book.dmm.com/detail/b900tkds00411/
「サッカーでデスゲームをやる」というテーマが、面白そう…だとみせかけて、別に、中身は普通に熱いスポ根漫画


ラグナクリムゾン
https://book.dmm.com/detail/b999asqex03087/
無茶苦茶強いvs無茶苦茶強いみたいなのがよい


葬送のフリーレン
https://book.dmm.com/detail/b600ysgk01887/
まあ当然もうみんな読んでると思いますが… 原作は読んでない

追記: 何故か原作小説があるのだと思い込んでたのですが、なんかの勘違いでした
(https://twitter.com/n_soda/status/1435634193636098052)

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どうなんですか → ごめんあんま違いわからん。違いがわからない程度に困ってはない


追記: .pam_environment は使えなくなったようです。代替の方法は…誰か教えてくれ