Syntax highlighter

2015-09-29

暗号ライブラリ (別題:実用Scheme)

Schemeは黒板言語だと言われたりするのだが(概ね認める部分もあるが)、プログラミング言語は実用されないことにはコミュニティも広がらないだろうということで、完全R7RSのみで暗号ライブラリを作っていたりする。ちなみにR6RS処理系用はindustriaがあるので、そっちを使った方がよいと思われる。

ライブラリの名前はAeolus(アイオロス)。まぁ、そういうことです。基本的にはSagittariusで実装されてる(crypto)ライブラリに似せた感じのAPIにしてある。使い方は大体こんな感じ。
(import (scheme base)
        (aeolus cipher)
        (aeolus cipher aes)
        (aeolus modes ecb))

;; 128bit key
(define key (string->utf8 "1234567890123456"))
(define cipher (make-cipher AES key mode-ecb))

;; 16 octet block
(cipher-encrypt cipher (string->utf8 "It's top secret!"))
;; -> #vu8(230 1 210 64 10 131 72 18 222 112 210 129 170 236 243 42)
パディングとかはまだ実装してないので、自前でデータをブロック長にする必要があったりする。

以下はここにあるR7RS準拠の処理系での動作チェック。部分準拠のものは試してない。

完動(全テストパス)
  • Sagittarius 0.6.8
  • Gauche 0.9.5 (HEAD)
  • Larceny 0.98 (ただしパラメタのテストはtest-errorの実装がおかしいので動かない)
  • Chibi Scheme (23ac772e3a)
テスト失敗
  • Chibi Scheme 0.7.3 (AESのテストがこける。SRFI-33っぽい、使わないようにしたらテスト通った)
動かん
  • Foment (複数のバグを踏んだ)
  • Picrin (パスの通し方が分からん)
  • Kawa (同上)
未検証
  • Husk (Haskellいれるのだるい)
PicrinとKawaはなんとか試してみたいのだが、いかんせんライブラリパスの通し方が分からんので手が出せない。誰かテストしてくれないかな(チラ その他リストには載ってないけど動いたとかの報告があると嬉しいなぁ(チラ

とりあえずDES、Triple DESとAESをサポート(というか、当面はこれだけの予定。Blowfishとか欲しい人いる?) 以下は当面のTODO
  • パディング(パラメタにするか明示的にユーザにやらせるか悩み中)
  • ハッシュ(MD5、SHA-1、SHA-256、SHA-512等)
  • MAC(HMAC、CMAC辺り)
  • RSA
  • PKI(X.509証明書とか。ここまでやるとほぼSagittariusの焼き増しに・・・)
 これくらいあるとTLSとかSSHとか実装できそう。

なんでこんなの作ったのか?


上の方に書いたのと被るけど、○○がないからSchemeは使わない(使えない)と言われるのが嫌だったから。仕様内だとソケットやスレッドがないのでいろいろ厳しいんだけど、そこに依存しないピュアSchemeなライブラリを書いていけばそのうち人が増えるのではないかと。黒板言語と呼ばれる理由の一つに実用的なライブラリが圧倒的に足りないというのがあると思うので、そこを何とかしていけばいつかきっととか。以前書いたPostgreSQLバインディングもそんな気持ちからというのはある。(Scheme使ってPostgreSQL使ってるっていう人の方は少ない気がするので、ちとニッチ過ぎたというのはあるが・・・)

まぁ、後は仕事で暗号関係を使わなくなってきたので、忘れないようにというのもある。誰にも聞かれないと思うけど、一応動機。

2015年9月30日追記
Chibiのバグが直されたので完動に追加。仕事が速い。

2015-09-24

process-wait with timeout argument

Recently, I'm writing own CI task on my local machine. (it doesn't mean I quit others when it's completed but just for fun.) Then, I've noticed that it might be convenient to have timeout argument on process-wait instead of using timer to poll every 500 ms (or whatever). So I've implemented it, now you can use like this:
(import (rnrs) (sagittarius process))

(let ((p (call "sh" "sleep_forever.sh")))
  ;; wait for 5 seconds. can also be time object.
  (unless (process-wait p :timeout 5))
    ;; it returns #f if timed out. so kill it
    (process-kill p)))
Now, I don't have to make timer to check. Very convenient :)

TL;DR


From here is the description of underlying implementation. This is not something you may be interested in but simply for my memo (and hope that somebody would indicate better solusion).

Sagittarius supports both Windows and POSIX environment. On Windows, the story was very simple, I just needed to call WaitForSingleObject with process handle and timeout millisecond. Hurray done!. I like this abstraction that API can handle almost any kind of handle. (Most of the time it's a headache to support Windows but sometimes it's easier than POSIX.)

On POSIX, on the other hand, it doesn't have timedwaitpid or something like that. I've asked the teacher, Google, what would be the solution. The first hit was this: Waitpid equivalent with timeout?. Its best answer doesn't seem the best answer since entire process would be affected. Plus, it would always wait for specified timeout amount of time which is not something I want. The most useful pointed one looks nice if POSIX has a portable way to get standard output file descriptor from pid. Though, there seems a way to do it using ptrace(2). (See reptyr(1) and  its source). I haven't looked into its detail but, in my understanding, it opens given pid process with ptrace(2) and calls dup(2) on that process (ptrace_remote_syscall does this black magic I think). It'd be nice to have it if I can do this all platforms Sagittarius supports. However not an easy task to do it without having real environments (e.g. OS X is only on Travis CI).

Go easy


What I wanted to do is waitpid with timeout. So I just need to have a watch dog which alerts either timeout is happened or the target process is finished. Well, the easiest one I could think of was thread with pthread_cond_timedwait(2).

The idea is pretty much simple. It goes the following steps:
  1. Create a thread with the thread entry which calls waitpid
  2. Call pthread_cond_timedwait.
    1. If this return ETIMEDOUT, then send signal to the thread and return #f
    2. Otherwise return the return code.
Done! What an easy solution! (There was a stupid mistake. I didn't know pthread_join can't be called with detached thread. Though, interestingly, it worked on FreeBSD, why?)


Issue


Well, if I can say this is a perfect solution, I'd be super happy but of cource this has an issue (for now only one I'm facing!). Because of the limitation of waitpid (2), the pid can be waited must be created by the parent process means Sagittarius script. Thus processes created by pid->process can't be passed (well this is not only for timeout argument but entire procedure issue, though). If this happens, then ECHILD is raised (see waitpid(2)).

I haven't got any problem with it but if would, then I need a better solution (maybe set PPID to running process? but how?). But for now, I'm happy enough and I believe there's very few situation which users want to wait non child processes.

Again, this isn't an issue on Windows. I don't care good or not but I like it.

2015-09-22

SMTPクライアント

何かが失敗したときにメールを飛ばせると便利かなぁと思い書いた。こんな感じでメールが飛ばせる(サンプルはドキュメントから)。

(import (rnrs) (rfc client))

;; creates SMTP mail object
(define mail 
  (smtp:mail
   (smtp:from "Your name" "your-address@example.com")
   (smtp:subject "Subject")
   "Message"
   (smtp:to "recipient@example.com")))

;; creates an SMTP connection
(define smtp-conn (make-smtp-connection "your.smtp.server.com" "587"))

;; connect to the server
(smtp-connect! smtp-conn) ;; returns SMTP connection

;; Authenticate if required.
(when (smtp-authentication-required? smtp-conn)
  ;; NOTE: only AUTH PLAIN is supported for now
  (cond ((memq 'PLAIN (smtp-connection-authentication-methods smtp-conn))
         (smtp-authenticate! smtp-conn (smtp-plain-authentication
                                        "username"
                                        "password")))
        (else (smtp-disconnect! smtp-conn)
              (error #f "authentication method not supported" 
                     (smtp-connection-authentication-methods smtp-conn)))))

;; Send it
(smtp-send! smtp-conn mail) ;; returns SMTP connection

;; Clean up
(smtp-disconnect! smtp-conn)
メールを作る部分は利便性を高めるためにマクロを用意してて、これの嬉しい点としては、記述力が高いこともあるけど、以下のようにメールをテンプレートとして外部ファイルに書き出しておいて、readevalで手軽に作成することができることもある。
(define mail
  (eval (call-with-input-file "mail.scm" read)
        (environment '(rnrs) '(rfc smtp))))
今のところは考えてないけど、メールのソース(MIMEテキスト)からメールをパース・生成するというのがあってもいいかもしれない。(その前に認証をもう少しなんとかしないとという感じではあるのだが。PLAINだけとかいくらなんでもねぇ・・・)

 一応RFC5321に書いてあるコマンドは全部実装してあるが、拡張とかは全然だし、エラー処理とかもまだ大分甘いので使って直していくという感じ。

2015-09-11

call/ccで嵌った話

call/ccというよりはguardなんだけど。

エラー処理をしたいとか、エラーが起きても処理を継続したいという場合はままある。そういったときに使えるのはguardであることもまぁ周知の事実だと思う。これから提示する例も常識的に理解されているものかもしれない。

まずは以下の例を見てもらいたい。
(import (rnrs))
;; (import (scheme base) (scheme write))
;; (define mod modulo)

(define count 100000)

(define (run)
  (let loop ((i 0))
    (if (= i count)
        i
        (guard (e (else (loop (+ i 1))))
          (when (zero? (mod i 5))
            (error 'who "dummy"))
          (loop (+ i 1))))))

(display (run)) (newline)
(flush-output-port (current-output-port))
これをみて、「あぁ、これはまずいわ」と一目で分かったら以下を読む必要はないです。

これがまずいプログラムだということは既に書いているのでいいとして、何がまずいか。問題になるのはguard内で外側のloopを呼んでいること。一見すると問題ないように見えるのだが、多くの処理系でguardの実装にcall/ccを使用しているのが問題になる。実装例:SRFI-34
参照実装を展開して簡潔に書くと以下のようになる。
(define (run)
  (let loop ((i 0))
    (if (= i count)
        i
        ((call/cc (lambda (k)
                    (let-values ((args (loop (+ i 1))))
                      (k (lambda () (apply values args))))))))))
はい、末尾再帰じゃないですね。なのでスタックがあふれます・・・orz

実際のところとして、R6RS的には末尾再帰になることを要求しているので上記はスタックがあふれるとまずいのだが、(嘘ついた。<cond>を<body>と空目した。)これが問題なく動いたのは確認した中ではChezとRacketだけ。(GuileとVicareは試してない。) もちろん、この2つはスタックを拡張して動かしてるだけかもしれないけど・・・ちなみにR7RSは末尾再帰であることを要求していないので、上記は動かなくても問題ない。

この挙動で嵌ったの実は2回目で、3度目があると嫌だなぁと思ったので適当に書き記しておく。 しかし、どうやったら末尾再帰なguardが実装できるんだろう?参照実装では無理だよなぁ?

追記:
直した。https://bitbucket.org/ktakashi/sagittarius-scheme/commits/7bab13c1e83820eda28fc7878b14209fe1b87df3?at=default

追記の追記:
Shiroさんとのやり取りで上記の修正が正しいのか不安になってきた。っが、問題になるケースが思い浮ばない+スタック消費しないのでこのままで行くことにする。

Problem of hop on hop off projects

Hop on hop off projects is the term I made. This means you join a project in short term, then join other project in short term, like hop on hop off tour buses. (I just don't know any word describes such a style of driving project, drifting?)

I'm currently working with kind of scrum environment. Why kinda? It's because sprint period is rather longer than usual (4-5 weeks) and no standup meeting. The same part is that each sprint I get new task(s). By now, the tasks I've got assigned were not really related so each time I need to look into something I don't know (of course product specific thing). Thus hop on hop off projects.

It might be only me but if I don't have long term commitment of a project, then I lose interest and start writing crappy code. This is because I start thinking that "I would move to next something I don't know anyway why should I write maintanable code?". Probably, I don't feel any responsibility to the code I'll never see in future. (Plus, the current code base is really pile of shit, I don't want to swin into that. Too risky...)

What happen if I'm such a state? For example:
  • Start using copy&paste instead of extracting common use-case somewhere usable place.
  • Using magic number/string as everybody is doing.
  • No tests (well, I don't think there's a culture writing a test in this company...)
These are happening right now. Of cource I know I'm not doing right but risk is too high if I touch/refactor something without tests. I do what I suppose to do but I'm not those highly motivated people so I don't much care as long as I don't see it anymore.

The funny thing about this is that my company is actually developing one product however they don't assign to the same project (so far) or don't have long term assignment. Each task must be done at most a month. I understand that's the basic idea of scrum. But by now, I can only see the greate failure, such as:
  • Wrongly abstracted classes
  • No tests
  • Copy&pasted code
  • Only few people know the structure of code/architecture
  • No refactoring (of cource, there's no efficient tests!)
  • etc.
I'm such a lazy person so I'd write as maintanable as possible if I need to maintain the code. But if I don't have to, this laziness seems to take into horribly.
Or maybe I'm considered as one of useless developers so they don't want me to do anything but piling crap. That's fine by me, as long as they pay my salary.

2015-09-09

ハッシュテーブルSRFIs

ハッシュテーブルに関するSRFIが2つ提出された。一つはJohn Cowanの「SRFI-124: Intermediate hash tables」でこれは既存のSRFI-69の互換性を保ちつつ拡張するというもの。もう一つはTaylan Ulrich Bayırlı/Kammerの「SRFI-126: R6RS-based hashtables」でこれは名前からも分かるようにR6RSで標準化されたハッシュテーブルを拡張するもの。SRFI-126はweakハッシュテーブルを要求しているのでこちらを実装すればもう片方は実装可能という感じである。(bimapをどうするかとかはあるが、Schemeで実装してしまえばいいわけだし、気にしないことにする。所詮別の型だし。)

これだけなら特にネタにもならないのだが、現状SRFI-126はweakハッシュテーブルと通常のハッシュテーブルの操作を同一の手続きで行えることを要求している。インターフェースの統一という感じだし、実用を考えればわざわざ「weak-hashtable-ref」とか書かずに「hashtable-ref」でアクセスできた方が楽というのはあるだろう。問題はどうこれを実現するかということだ。普通に全ての手続きでハッシュテーブルのタイプを場合分けしてもいいんだけど、泥臭い上に拡張性が低い。別のハッシュテーブルが追加されるという可能性は低いといえば低いが、ないわけでもないだろう(concurrentハッシュテーブルとか)。とすると、もう少しマシな方法を考える必要がある。

現状Sagittariusはハッシュテーブルとweakハッシュテーブルは完全に別の型としているのだが、これを以下のようにするとなんとなく拡張性が高くなりそうな雰囲気がある(あくまで雰囲気)。
          +-----------+
          | hashtable |
          +-----+-----+
                |
      +----------+-----------+
      |                      |   
+-----+------------+ +-------+--------+
| normal hashtable | | weak hashtable |
+------------------+ +----------------+
まぁ、普通というか、ひねりも何にもなくインターフェースと実装を分けるだけという。実際にはこれにmutableとimmutableのクラスを追加してやろうかなぁとも考えている。こうしておけば後で意味不明なハッシュテーブルが現れてもそれなりに問題なく動くことが期待できそうだ。

このSRFIは出てきてまだ数日なので上記の変更を入れるかを決めるのは時期尚早な気がする。ただ、この変更自体はやってもいいかなぁとも思えるのでどうしようかなぁというところ。

2015-08-28

OS X support and Travis CI

Travis CI doesn't support Bitbucket so I didn't use it until now. I knew there's a way to use it, more precisely, there's a service which synchronises Bitbucket's repository to Github (BitSyncHub). But I didn't use it since there are couple of CI service which support Bitbucket (e.g. drone.io). Now, I've heard that Travis CI supports OSX so I wanted to use it. Using BitSyncHub wasn't difficult at all (so if you want to use Travis CI, it might be worth to consider). Enabling multiple OS support requires dropping a line to their support. No problem. Then I've got the environment, yahoo!!

OS X is, I believe, considered POSIX OS in most of the case. So I was hoping that Sagittarius would work without any change. Well, it didn't. When I write OS specific code, I refer POSIX spec to make sure I'm writing portable code. Was I doing right? I think so because the code worked on FreeBSD without any change which is also considered POSIX compliant OS. The pitfalls of OSX were the followings:
  • sem_timedwait is not implemented (linker error)
  • sem_init is not supported (can be compiled but an error)
  • Passing O_TRUNC to shm_open is an error.
Well, not that much things but pretty much annoying. Especially the first one. I've created a patch to make 0.6.7 be compiled so that CI server can build it.

Long time ago, Sagittarius got a pull request which made it work on OSX. The PR also contains a fix for libffi search path. It requires to specify the path explicitly. Which I think fine as long as you have control of the environment. However on CI server, we don't know until when the version is there. So I've written kind of solution to fine libffi in build process. So now, you can simply build like the following:
$ cmake .
$ make
It does kinda ugly thing internally but it's working so I'm happy with it.

Then I've experienced build failure number of times (including stupid mistake), finally got the successfull build.

Now, I can say Sagittarius supports OSX again.

2015-08-17

プログラミングにおける公私

駄文

高校で物理の教師が担任だったときに「数学に疲れたら国語を勉強して気分転換して、一日10時間勉強する」とか言われた記憶がある。勉強すること自体に疲れるのにどうやって別科目をやって気分転換するんだ?と疑問に思ったことがある。あれから15年ちょっとなんとなくあの教師の言っていたことが分かった気がする(遅い)。

僕の職業はプログラマで趣味(の一つ)もプログラミングである。職場で書くコードは大なり小なり制約があり思い通りに書くことはできない。言語の制約だったり(Java辛い)、積みあがった糞を崩したくないという精神的枷であったり、あんまり深く追求したくないという己の弱さだったりとまぁいろいろだ。例えば今の職場は、ユニットテストを書く習慣があんまりないかつテスト自体を書くのが驚くほど辛いので既存のコードを弄るのが怖いという個人的には致命的な枷があり、コードを書くのが辛いのである。(そんな環境を変えるという選択肢もあるかもしれないが、そこまで会社に思い入れはない+現状を変えたくないのに権力を持った人がいるので戦ってまで変える気もない。給料分だけ働きます状態。)

そんな状況でコードを書いているといろいろとストレスがたまる。特に現状を変えないように無理やりAPIに切り出す作業とか個人的に大分辛い。そうすると趣味で書いてるプログラムで思いっきり変更加えてストレスを発散しているのである。まさに「プログラミングでプログラミングの疲れを取る」という傍から見たら意味不明なことをしているわけだ。

プログラミングの一つの醍醐味として、自分の思ったとおりのプログラムを作ることができる(可能性がある)というのがあると思っていて、それは例えばパズルのピースがぴったりはまるような感覚で上手く抽象化できたとか、本来なら1000行くらい書く必要があるものを100行まで圧縮できたとか(マクロ中毒)、形は違えど思い通りになる感覚がいいのである。個人的にはこれが得られないとストレスになるらしく、どうしようもなくコピペが要るとか、あまりに酷いコードだけどテストがないから直せないとか、仕事で書くコードはそういったものが趣味で書くものより多いみたいである。

自分が書くコードがきれいとか上手いこといっているとは思わないし思えないが、それでも思い通りに書き換えることができる(もちろん動作は変えないで)というのはやはりストレスを発散することができるようである。特に不要なコードをばっさり削ったときの爽快感は一度味わうと止められない。趣味のプログラミングで気分転換をするときは何かしらがごそっと変わっている可能性がある。いいか悪いかは言及しないことにする。

取り留めなく終わり。

2015-08-14

Renaming identifier (solution of pandoric macro)

I've found a solution for the bug described on the article: pandoricマクロ. It was a rather simple solution.

There were 2 issues and one was a bug.
  • Making a global variable strips syntax information of the given identifier (bug)
  • Explicit renaming doesn't rename when identifiers are bound
The first one was a very simple bug, on the compiler if define has an identifier for its binding's name, then it shouldn't strip. That's it. Though, this isn't a good solution because if the identifier is bound in other library then the binding would be created not the one creating a binding but the one created the identifier. I think it's not a big deal but rather weird.

To resolve the weirdness, the identifier needs to be renamed. On Sagittarius, identifiers internally contain its identity which is a sort of history when the identifier is renamed. If the identity is #f, then it's a global identifier (means almost the same as raw symbol). Now, as far as I remember, each identifier, which reached to define and contains identity, are renamed means created in macros and it should be safe to change its name to unique symbol which is done by compiler via rename-pending-identifier. So I've added extra check to change the identifier name.

The benefit of this change is not only making R7RS syntax-rules work the same as R6RS one but also make R6RS datum->syntax works more R6RS compliant. More precisely, it resolved this issue. So now this won't work:
(import (rnrs))

(define-syntax define/datum->syntax
  (lambda (x)
    (define (concat n1 n2)
      (string->symbol
       (string-append (symbol->string (syntax->datum n1))
              "-"
              (symbol->string (syntax->datum n2)))))
    (syntax-case x ()
      ((_ name1 name2 var) ;; oops
       (with-syntax ((name (datum->syntax #'k (concat #'name1 #'name2))))
     #'(define name var))))))

(define/datum->syntax n1 n2 'bar)

n1-n2
;; -> error
(though, I've also found a piece of code depending on this bug...)

In my understanding, this type of renaming isn't required on R7RS. So this is a valid R7RS script:
(define-syntax defbar
  (syntax-rules ()
    ((_ name)
     (defbar name t1))
    ((_ name t1)
     (begin
       (define t1 'bar)
       (define (name) t1)))))

(defbar foo)

t1
;; may or may not an error
For example, Chicken Scheme returns bar. (For my preferecne, if identifiers are bound in macros, then it should be renamed as R6RS requires, but I can't do much about it.)

2015-08-10

手抜き力

最近日常的に割りと限界まで自分ができることを詰め込んでいるのではないかということに気づいたのと、それだとまずいなぁと思ったので自戒を込めたポエム。

一生懸命という言葉がある。元々は一所懸命という言葉だったのが、どこかで間違って一生懸命となったらしい(要出展)。僕は人生是すちゃらかをモットーにしているのだが、どうも何かを頼まれたりやろうと思ったりすると加減というものが効かない性分でもあるらしい。頼まれたら確実に不可能でない限り引き受けるだろうし、やると決めたら割ととことんやるので大抵どこかで息切れをする。これらのことが期限付きもしくはゴール付きのことであれば終わりがあるのである程度大丈夫なのだが、無期限もしくは終わりがないものだと問題になる。

例えば100m走を思い浮かべればどんなことかイメージしやすいだろう。100m走であれば、100m全力で走った後は失速しようが血を吐いて倒れようが目的は果たしたのでそれ以上に何かを求められることはない。それがマラソンだったらどうだろうか?100m走って止まってもまだ終わっていない。残り42.095km走らなければならないのだ。

話を一生懸命に戻してみよう。一生を懸命に生きる、すばらしい言葉だと思う。でも人生を80年と考えて常に全力疾走できるだろうか?残念ながら僕のような凡人には無理である。30数年生きたが24時間365日の内5割は手抜きして生きてきたと思う。それがここにきて手抜きの割合が多少減ってきたのである。別に大したことではない。例えば掃除を隅々までやるとか、毎日3食作るとか、そういった日常的なことの積み重ねで手を抜かなくなってきているのである。もちろん趣味の範囲とかもそれなりに拡大しているし、最近だと書類を集めるのに奔走したりとかいろいろある。

単に年を取って体力が衰えただけともいえるかもしれない。しかし、それであればより現状の自分の限界を確かに見極める必要がある。朝起きて、朝食作って掃除して買出ししてジムに行ったら15時くらいなんだけど、もう体力がないとかになってしまうと、何かあったときに全く動けない(割と切実)。

完全に自業自得なこと書いてるんだけど、ここ数週間ちょっといろいろあって上記の何かあった状態になっているのだが、ジムに行くのをキャンセルしても何かあったの何かが帳消しするぐらいに体力を持っていくので一つ一つのタスクを手抜きしないと倒れる状態になってたりする。しかも、この何かは無期限に続く系のものなのでふとこんなことを書いてたりする。若いのは精神年齢のみであるので肉体年齢相応にしないとという自戒。

2015-08-09

pandoricマクロ

SchemeでCLのpandoricマクロを実装したらSagittariusでは動かないというのを捕捉した。コードをGistに貼り付けてもらった。これ。正直見ただけで、「あ、これ動かないやつだ」分かるのが嫌だったが、一応確認してみた。うん、動かないね・・・

一応言い訳をしておくと、R6RS版のsyntax-rulesなら動く。問題になるのはR7RS版のsyntax-rules。何度もブログに書いてるから知ってる人は知ってると思うけど、SagittariusではR7RSで追加された拡張を実現するために、R7RSのsyntax-rulesはChibi Schemeから移植したものを使っている。これは大抵の場合で上手く動くんだけど、上記のような、テンプレート変数で生成した一時変数を別ライブラリで大域に束縛すると動かなくなる。

もう少し短い例だと以下のようなコード:
;; foo.scm
(define-library (foo)
  (export defbar)
  (import (scheme base))
  (begin
    (define-syntax defbar
      (syntax-rules ()
        ((_ name)
         (defbar name t1))
        ((_ name t1)
         (begin
           (define t1 'bar)
           (define (name) t1)))))))

(import (scheme base) (scheme write) (foo))

(defbar boo)

(display (boo)) (newline)
;; -> error
#|
sash -r7 foo.scm
|#
(scheme base)(rnrs)にすると動く(define-libraryは変更する必要はない)。何が問題かといえば、defbar内で細くされたテンプレート変数は、そのマクロが定義されたライブラリを内部で保持する識別子となるため、展開後に参照しようとするとそんなものないと怒られるのである。これは健全性を保持するためにそうなっているのだが、一時変数を大域で束縛するとそれがあだになるのである。

ではどうするかなのだが、一番確実なのはsyntax-caseで実装するというものなのだが、これも実は内部的な問題がある。コンパイラ内でマクロを使っているのだが、このマクロはerで実装されたsyntax-rulesであるということに大分依存している。単純にerの方が作りが単純なので識別子が保持する環境とかをあまり考えなくて済むというだけなのではあるが。さらに、これをやるとR6RSとR7RSで使用する_...を分けなければならなくなるのであまり美味しくない。(理由はsyntax-caseにある)

次にやれそうなのは、syntax-rulesの実装を変えることなのだが、これやってもerで作ったマクロに問題が残ることになるので、近い(遠いかも)将来、erがR7RS-largeに組み込まれた際にいやな感じになる。(のでやらない)

残るは少しadhocになるが、大域に束縛された識別子の定義位置が別ライブラリだった場合に同一の識別子の位置を無理やり束縛されるライブラリに変更するとかになる。ぱっと思いつくパターンでは動くような気がするんだけど、これだけadhocな変更だと大体どこかでほころびが出ることが過去の経験から分かっているのでやるなら思いつく限りのパターンをテストしないとという感じになる。(まぁ、似たようなことをsyntax-caseでやっているので動くとは思うんだけど、どうだろう?)

ちと考える必要があるなぁ・・・

2015-08-06

Safer thread termination (2)

I think I've found a (imperfect) solution to do it.

Goal


The goal is pretty simple. No crash, that's it. Optionally, releasing resource as much as possible. But the resource in this case is not about Scheme world or Sagittarius created, it's OS resource such as allocated stack or so.

The problem


Yes, it's the problem. The problem was sometimes it crashed with 0xC0000005 (access violation, SEGV in POSIX way). The termination process was described in previous article (Safer thread termination) . The cause, in short, was interrupting Eip or Rip may break call stack frame.

As my conclusion, if the Scheme process went into deep inside of C function call, then the program counter is overwritten, the call stack may get broke. So when the process tries to return from RaiseException however there is no place to return or returning invalid address. (This may not be true but seems like it.)

Comparing stack pointer was not enough


In previous article, I've written to do it. It does prevent the error when the thread has already returned from entry point however it didn't resolve returning from deep stack address. So I need to find one more thing.

The issue is breaking call stack. Means, if I can restore it until the thread entry function is called, then the call stack is not broken and can return properly.

jmp_buf?


If I need to restore the stack frame of certain point, then setjmp and longjmp seem the things I need to use, instead of calling RaiseException. So I've put setjmp before calling Scheme world process. Then the thread-terminate! interrupts the process to the C function which calls longjmp.

Not a perfect solution


Unfortunately, this isn't a perfect solution. It works most of the time and, I think, should be good enough (so far I don't get crash in my test case). However, the following code may not work:
(thread-terminate! (thread-start! (make-thread (lambda () #t))))
The problem of this piece of code is that the thread may not be terminated. If the thread couldn't reach the point where setjmp is called, then thread-terminate! would call longjmp without proper jmp_buf. Or the thread wouldn't be terminated if it didn't reach the internal thread entry point. Who writes this crap? Who knows.

This may not be a perfect solution but at least less possibility to get crashed. Thus it's safer than before. So, for now, I'm happy with it.

2015-08-04

Safer thread termination

Terminating a thread is a dangerous operation (AFAIK). So this shouldn't be done in general. However I've wrote the library (util concurrent) which uses thread-terminate! to finish tasks forcibly. As my understanding, as long as you free all resources held by the thread, terminating thread isn't that badly wrong. Well, if this was the conclusion, then I wouldn't write this. It actually works fine on POSIX environments I usually test, including Cygwin, however not working properly on Windows.

Windows has the API which terminates a thread, called TerminateThread. I, however, don't use this because of the following reasons:
  • It may not release all resources
  • There is no way to handle after termination
If the resource aren't released, then it may leak eventually. I don't use Sagittarius on 24/7 service so this might be a trivial issue but you'll never know. So it's better to have as safe as possible.

If you don't use TerminateThread, then there's, afaik, not many choice to do it. The way I've chosen is using CONTEXT. The basic process is the followings:
  1. Suspend the target thread
  2. Check if it's active
  3. Get thread context
  4. Set program counter to the function calls RaiseException
  5. Resume the thread
The thread caller wraps the thread function with _try and _except, so the thrown exception will be caught.

Until here, there seems nothing wrong and works fine. Well no. This works most of the case however at some point you may get a context which contains no call frame of thread caller function. I think this means either thread is almost terminating or it's finished but still active. Then you'd get access violation error.

Now, what can I do? I think I'll try to compare stack pointer. Luckly, Boehm GC has base stack pointer on each thread. So if I can get this and compare with the thread context stack pointer, I might be able to detect if the thread is already finished (or at least returned from the thread function of Sagittarius) or not.

If you know better way, please let me know.

2015-07-27

語学学習

ふとしたことから新しい言語を学ぶことについて議論をしたのだが、そこからなんとなく自分の中の言語感覚が分かったような気がするのでメモ。単なる駄文。

言語間の距離


日本語は欧州で話される言語から見ると最も遠いところにある言語の一つである。(参照: Language Difficulty Ranking - Effective Language Learning) これはどうしようもない事実なので受け入れるしかない。思えば中学で初めて英語に触れたときに、日本語との類似点を見出せずとにかく意味不明なものであった記憶がある。ELT(今はALTか?)で来てたアメリカ人(だったはず)に「英語好きか?」と
聞かれて「パズルみたいだから、好きだ」と答えたのだが、答えられた方は意味が分からないという顔をしていた気がする。それくらい意思疎通の道具ではなく、何かしらクイズみたいなものだったということである。

オランダではオランダ語が話されているというのはある意味当たり前で、6年も住んでいれば多少は喋れる、理解できるようにはなるのだが(もちろんそれなりには勉強しているが)、僕の中のオランダ語は基本的にオランダ語との距離が近い英語をベースにしている。英語とオランダ語の間は割りと一対一の関係に近い。それとは逆に日本語と英語の間には言語間の意味を言語ではなくイメージで捉えるような抽象的な層があるように思われる。これら3つの言語の関係を図にするとこんな感じになる。
  +-----------------+
  |                 |
  |     Dutch       \
  |                 |\
  +-------++--------+ \
          ||           \
          ||            \                     .........
          ||             \               ...........   ......
          ||              \         .....                 ...
          ||               \    .....                       ...
  +-------++--------+       \ ...                             ..             +-----------------+
  |                 +--------..                                  ..----------+                 |
  |    English      +------..      Abstract language layer        ..---------+    Japanese     |
  |                 +------.                                       ..--------+                 |
  +-----------------+      ..                                      .         +-----------------+
                             ..                                   ..
                               ...                          ......
                                   ..         .. ............
                                     ................
線が多い方が密に繋がっているとする。日本語と英語の繋がりは(例外もあるけど)大体言語ではない何かで繋がっている感じ。なので英語で話してるときは日本語で考えることが辛い。逆もまた叱り。逆にオランダ語は抽象空間を経由しないので割りと簡単に英蘭をスイッチできる。言語間の距離が離れている言語を学習する際はこの違いを吸収する層の構築が重要になるのではないかと思っている。

オランダ語話者から見た英語


そこまで具体的に聞いたわけではないのだが、オランダ語を母語とする人からみた英語というのは母語+α(下手するとマイナスα)くらいの感覚のようである。学校で一応文法や英語の文章がどのように構築されているかとかやるらしいのだが、学校でやったら後は忘れても問題ないくらいで細かいことは気にしなくても喋れるようだ。人の頭の中は覗けないので実際のところはどうかは分からないが、おそらくこれくらいの勢いで繋がっているのであろう。
  +-----------------+
  |                 |
  |     Dutch       |
  |                 |
  +----+++++++++----+
       |||||||||
       |||||||||
       |||||||||
       |||||||||
       |||||||||
  +----+++++++++----+
  |                 +
  |    English      +
  |                 +
  +-----------------+
方言とまでは行かないが、かなり近い言語であることは間違いないのでここまでではないにしろ英語を話せるオランダ人の中ではこれくらい近いものではないだろうか。なんともうらやましい限りである。

オランダでは(多分欧州の多くの国では)高校卒業までに少なくとも2ヶ国語を学ぶのだが(オランダでは英語とフランス語かドイツ語)、どちらの言語も日本語に比べればはるかに近い、それこそ限りなく0に近いレベルなので(言いすぎだが)上記の図の近くにもう一つ言語が追加されるレベルのものだろう。

オランダ語話者から見た日本語


実はこれが本題。当然だがオランダ語と日本語にはほとんど類似点はない。文法、発音、動詞の格変化挙げればキリがないが、本当に何一つない。まぁ、これは英語でもいえることではあるが。これくらい何もないと学習するさいの取っ掛かりがないように思える。平面に点が2つあるだけとかそんなレベル近い気がする。(これは憶測だが)それまで言語学習といえば母語と紐付けて考えることができたものが、いきなり手探りになるので近寄りがたい感じになるのではないだろうか?

個人的には一度抽象化の層を構築してしまうとなんとなく他の言語を学習するコストが下がる気がしないでもない。もちろん発音とか聞き取りとかは物理的な問題があるのでそれなりに時間がかかるが、頭の中の切り替えは大体同じようにできる気がしている。

なんでこんなことを思ったかというと、日本語を話したい言ってはいるがこの取っ掛かりのなさに絶望気味になっているという話しを聞いたのだ。僕はこの絶望も20年前に味わっている+義務教育という性質上克服する以外に逃げ場はなかったのでなんとなくなんとかなってしまったという。ひょっとしたら言語の距離というのは一度克服してしまうと後は楽になるのではないのかなぁ、と思ったのであった。オチなし。

2015-07-16

あとらんだむ

時間があるときにまとめてとも言う。

MSVCとスタック

最近AppveyorというWindows用CIサービスでもCIをし始めたのだが(なぜかx64版が0xc0000005で落ちるのだがなぜだろう、起動すらしてない感じに見えるのだが?)、試用期間が終わって無償版に自動移行した際に起きたスタックオーバーフロー例外が起きるようになった。起きている場所は毎回同じ。移行される前は動いていたテストなので不思議な感じがしていたのだが、原因がCPUが1個にされたためにテストケースがシングルスレッドで走ったため発覚したバグだった。

ちょっと前にCPUが1個のときはテストケースをシングルスレッドで走らせた方が速いということを確認したので、ランタイムでCPUの数を確認して適当にディスパッチさせるようにしたのだが、これが原因(もしくは功を奏したの)だった。問題になったのは10万くらいネストしたリストの書き出し。これくらいネストするとC側のスタックが尽きるのでスタックの深さが既定値(メインスレッドで1MB、子スレッドで64KB)を超えたら&i/o-errorを投げるようにしていたのだが、これが上手いこといっていなかった。MSVCは既定では1MBしかスタックを割り当ててくれないので、リンカオプション(具体的には/STACK)で8MBを指定していたのだが、どうもこのオプションでは上手く行かなかったらしい。とりあえずどれが上手く動くのか分からないのでC_FLAGSとCXX_FLAGSに/Fオプションを渡し、さらにCMakeが持っている2つの内部リンカフラグ両方に/STACKオプションを追加した。これで試すと手元の環境ではスタックオーベーフロー例外は起きなくなったのだが、Appveyor上ではまだ起きる。起動時にスタック領域を制限されるのか、Windowsサーバーの仕様なのかは不明だが起きるものは起きる。

どうしたものかと適当にGoogle先生にお伺いを立てたところ以下の記事を発見。

How to trap stack overflow in a Visual C++ application

_try_exceptを使って例外を捕捉したらVirtualFreeとVirtualProtectでスタック領域を元に戻してやるというもの。これいけるんじゃね?と思い早速追加。

https://bitbucket.org/ktakashi/sagittarius-scheme/src/031c6cbaf9c75df5815b7885a2c9ba5c34bb119f/src/writer.c?at=default#cl-1065

インラインアセンブラの部分は適当に変更(そうしないとx64ではコンパイルできない)。なんとなく動いているようである。

これとStackWalk64を使うとスタックトレースが取れそうな気がしないでもないので、組み込んだら原因不明の0xc0000005の発生場所が特定できるかもしれないなぁ。

タイムゾーン

どうもPOSIXやMSVC付属のCRTにあるタイムゾーン関係のAPIは使いにくい。というか、基本的にはタイムゾーンオブジェクトみたいな風にできないようである。別にシステムの時間とかを変更したいわけではなく、単にある地域のGMTオフセット等が知りたいだけなのだが、そういう使い方がやりづらい。Javaだとjava.util.Timezone(Java8からは非推奨になったけど)等があるのでなんとかできるのだろうとちょっと調べてみた。

結果、やれるけど割りと茨の道。Javaは自前のタイムゾーンDBを持っててそこから情報を取得している。Java8からはtzdb.datというファイルに変更されて、更新があってもとユーザがJREの更新を待つ必要がなくなったというのはあるが、OSから取得していないというところは一緒である。

タイムゾーンの情報は現在はIANAが管理していて、データ及びPOSIXの時間関係のソースはパブリックドメインで公開されている。そこに山があると登りたくなるのが登山家であれば、そこに問題があると何とかしたくなるのがプログラマである。別に面白みがあるものではないが、OSが上手いことAPIを提供してくれないのであれば、自前でなんとかせねばあるまいということである。

とりあえずFTPサーバーからデータファイルを落として、そいつらをS式に落とし込む部分までは書いたので後は落とし込んだ情報を元に時間をなんとかするだけなのだが、そこが面倒ともいう。とりあえずは、GMTオフセットと夏時間が取得できればいいのだが、今週末(というか明日)予定 している0.6.6のリリースには当然間に合わない。ただ、tzdb.dat相当のファイルをリポジトリに入れたくない(自動生成されるファイルを入れたくない)ということから、ここまでは今のうちにやっておかないと(0.6.6が提供するAPIのみで書けるようにしておくという意味)間延びするか、ポリシーに反してリポジトリを汚すかの2択になってしまうので。

IANAのデータ、閏秒のデータも入っているから何とかすれば外だしにできそうなのだが、何を血迷ったのかC側に入れてあるのでちょっと辛い気がしないでもない。まぁ、もう少し機能をScheme側に押し出してやればやれなくもないのだが、どうしようかね。


なんかもう一つ書くことがあった気がしたのだが、完全にわすれたようなのでオチもなくお終い。

2015-07-08

Conditions and stack trace

One of the things I don't want to see is stack traces. Whenever I saw this, I'd always be disappointed. There are basically 2 reasons: the first one is it usually means something went wrong, the second one is sometimes it doesn't show where the condition is actually raised. The first one can be considered a bug so I just need to snatch it. The second one is more for implementations issue.

Currently, Sagittarius shows stack trace whenever default exception handler is invoked, means no guard nor with-exception-handler. The stack trace is collected in the default exception handler. This is fine most of the time since I don't use them that much in my script. (well, I don't argue if it's good or not here.) However, sometimes I want a script fail safe or make sure it releases resources or so. Then I saw the fangs. As a simple example, you have the following script:
(guard (e (else (release-all) (raise e)))
  (open-something-and-fail-it)
  (release-all))
Suppose open-something-and-fail-it may raise an error and you want to release all resources after the process. Now, you saw a stack trace, what would you expect to be shown? I would expect where the root cause is raised. Or at least I can see it. However because the stack trace is collected in the default exception handler, you don't see those information at all.

It was okay until I had written a server program which shows a stack trace whenever unhandled exception is raised. If you write this kind of script, then you want to know which one is the actual culprit, server itself or the application program. As long as I'm writing both, it's just a matter of good old days printf debug but this is pain in the ass. If the stack trace shows where this happened, I don't have to do this type of thing in some cases. So I've changed the timing of collecting stack traces.

The basic idea is whenever raise or raise-continuable is called with compound condition, then it appends stack trace object. Only one stack trace object can be appeared in the compound condition. So if the condition is re-raised, then new stack trace object is created and the old one is set to the new one as its cause. It's pretty much similar with Java's exception. Of course, there are bunch of differences.
  1. Java's exception collects stack trace when it's created
  2. java.lang.Throwable's cause property may have root cause while Sagittarius' only takes stack trace object.
  3. The stack trace object is implicitly added, means given condition is copied entirely while Java's exception can be the same.
The item #1 is the biggest one. On Java, if you throw an exception created before the throw syntax, then the stack trace indicates where it's created. This can be very inconvenient like this type of case:
public class Foo {
  private Exception exn = new Exception();
  public void foo() throws Exception {
    throw exn;
  }
}
Don't ask me who would do this but the stack trace would be shown indicates the second line. (I didn't check the Java's spec, so this might depend on the implementation.)

The item #2 is because of implementation of condition. It flattens the given compound conditions if there are. For example, suppose you catch a condition and re-raise it with adding specific condition. The script would be like this:
;; suppose (fail) raises a compound condition
(guard (e (else (raise (condition (make-some-other-condition) e))))
  (fail))
In this case, the compound condition e will be flattened and merged into the new condition object. R6RS doesn't say how the condition procedure construct compound condition so it can decompose it by need.

The item #3 can be an issue. Suppose you want to re-use a condition and compare it by mean of eq? like this:
(let ((c (condition (make-error) (make-who-condition 'who))))
  (guard (e (else (eq? c e)))
    (raise c)))
;; -> #f
The raise procedure implicitly copy the given condition and adds stack trace object, thus the object wouldn't be the same one. I couldn't find anything mentioning this kind of thing on R6RS. So I think it's still R6RS compliant. However this might cause an issue in the future. (Using exception as a returning value or so?)

The reason why Sagittarius choose to collect stack trace  when condition is raised is because of the requirement of condition procedure. It's not so difficult to make condition procedure collect stack trace however this procedure must be able to take arbitrary number of conditions including compound conditions. So there is no way to specify which one is the actual root cause when multiple compound conditions are given. (Nobody do this? who knows!)

I'm kinda doubting that if I made a better choice. Especially item #3. But seeing irrelevant stack traces is much more painful. So I think I can live with this.

2015-07-03

Webアプリケーションサーバっぽい何か

時間というのは取れるときは取れるものである・・・

今更ながらにWebアプリ的な何かを暇を見つけて書いているのだが(世の中GUIでできるものはクリック一つでできた方が楽ですよ的な軟弱な考えに基づいている)、一ファイルに全部詰め込んで書いてるのが辛くなってきたのでいろいろいい感じに扱ってくれるフレームワーク的なのを書いたのでその紹介(と備忘録)。基本的にはPaellaの上(名前的には下だけど)に乗せてある何か。

極々簡単な何か


Githubから落としてきて以下のコマンドでインストール可能。
$ cmake .
$ make install
インストールしたら適当にアプリを作る。まぁ、こんな感じ。
$ plato-recipe.scm -i -a sample simple-app 
simple-appというディレクトリができているはずなのでそこに移動して、以下のようにサーバ起動。
$ sagittarius run.scm 
これだけやると、http://localhost:8080/sampleにアクセスできるはず。OKと表示されていたら上手いこと動いている。

仕組み


30分足らずで書いた何かなので、仕組みも糞もないくらい簡単ななのだが、端的に言えばディレクトリ決め打ちアプリケーションという感じである。上記の例だと以下のようなディレクトリ構造が作成される。
simple-app/
  + lib/
  + apps/
      + sample/
          + handler.scm
  + run.scm
handler.scmがマウントポイントのエントリーポイントになる。詳しくはソース見た方が早いレベル。

欲しげな機能


  • セッション管理の機能とか。現状クッキーを扱うライブラリとかないのでそこから作らないといけないという。
  • 設定ファイル的な何か。JEEでいうweb.xml的のがあるといいかなぁ。
  • マウントポイント別環境。
  • サブパス。今のところ一番sample/fooみたいなことができない。いるかどうかは別だが・・・

ちょっとCygwin上で動かしたらselect (2)の実装の違いにより動かなかったので、現在のHEADが必要。Linuxなら0.6.5でも問題なく動くと思う。

2015-07-02

プロセス間通信とセマフォ

書こうと決めてから1週間近くたってしまった。時間とは取れないものである。

Sagittariusにプロセス間通信用の共有メモリとその排他制御用のセマフォを入れた話。

プロセス間通信なんてソケットでもファイルでも何でもいいんだけど、もう少し軽量なものがあるといいかと思い共有メモリを入れた。っで、一つの資源に対して二つ以上の場所からアクセスがあると排他制御がいるということで、プロセス間で使えるセマフォを入れた。とりあえずこんな感じで使える。
;; process A
(import (rnrs)
        (sagittarius process)
        (sagittarius threads))

;; create a semaphore with initial counter 0
(define sem (make-semaphore "/waiter" 0))

;; opens shared memory. if this is the first process then it'll be created
;; with the size 256.
(define shm (open-shared-memory "/shared-memory" 256 (file-options no-fail)))

;; wait for the other process
(semaphore-wait! sem)

;; something was delivered
(let ((bv (shared-memory->bytevector shm)))
  (print (utf8->string bv 0 5)))

;; close and release
(close-shared-memory shm)
(semaphore-close! sem)
(semaphore-destroy! sem)

;; process B
(import (rnrs)
        (sagittarius process)
        (sagittarius threads))

;; open the semaphore created by the other process
(define sem (open-semaphore "/waiter"))

;; this must specify no-truncate option otherwise it may fail
(define shm (open-shared-memory "/shared-memory" 256 (file-options no-truncate)))

(let ((bv (shared-memory->bytevector shm)))
  ;; put some value
  (bytevector-copy! (string->utf8 "hello") 0 bv 0 5))

;; notify the other process
(semaphore-post! sem)
プロセスAは入力待ちプロセス。プロセスBは共有メモリ/shared-memoryに何か書き込んでセマフォのカウンタを一つ増やす。

正直共有メモリだとシェルから使いにくいのであんまり嬉しくないのが悲しいところ。本当は名前付きパイプも入れたいのだが、POSIXとWindowsでモデルが大分違うので上手いAPIを思いつかないでいる。(作成を考えなければどちらのモデルでも名前付きパイプは単なるファイルと変わらないので扱えなくはないのだが、せっかくなので何かほしいという話。)

なんでこんなのが入ったかといえば、最近仕事で使うツールを自前サーバに載せているのだが、サーバの再起動をリモートREPLからできると楽かなぁと思ったからというのがある。正直どちらもあまり上手く使われていないので今のところそこまでの恩恵がないという話もある・・・

2015-06-25

Platform specific issues

Recently I've faced to stability issues. The followings are the ones I've met:

Well, the one for Windows is kinda known for a while (except Windows Server one). These issues are categorised more or less platform specific issues.

The reason why I'm writing is because I have no idea why it happens and might be able to get some knowledge from comment (my googling ability is not high enought to find the solution). For example, the first one happens only on Arch Linux. The funny thing is that the reported bug didn't happen on my Arch Linux environment but different one mentioned on the comment. And never happened on other environment (e.g. Ubuntu or FreeBSD).

The second one happens only on my Linux CI environment. So I even can't debug. And, again, never happened on other Linux environment. (why?)

If you have any clue, please let me know.

2015-06-07

パラメータとスレッド(2)

前回の続き。

コードとか実装のアイデアというのは寝かせると浮かんでくるものではあるのだが、割と早めに浮かんできたので早速実装してみたという話。

Gaucheの動作はパラメータの初期値をグローバルに持っているから実現されている(それ以外にも手はあるのだが)という話から、とりあえず同様のことをしてみた。SagittariusではパラメータはSchemeで実装されているので実装ライブラリにWeakハッシュテーブルを持たせパラメータが参照される動的環境内に値がなければグローバルのテーブルから引っ張ってくるという実装。実装が簡単な上に効果は抜群で、前回のスクリプトはGaucheと同様の結果を返すようになった。さらに、Weakハッシュテーブルを使っているのでGCが走った際にどこからも参照されていなければ回収されるのでメモリの爆発もない。

この変更によるものではないと思うけど、プッシュしたらdrone.ioのテストがこけた・・・なんだろう?