IPC::Open3 を使って、子プロセスの標準出力と標準エラー出力をポーリングする。(Windows では動かなかった…)


Windowsでも動く続編を書いたので、そちらを参照ください。
IPC::Open3 を使って、子プロセスの標準出力と標準エラー出力をポーリングする。(Windows でも動くよ!) - ◆F99a.q8oVEの日記



とか言っていましたが、一時ファイルに吐かせる方法で書いてみました。

qx2_win が Windows 用、qx2 が Windows 以外(FD にたいして select が使えるプラットフォーム)用。 ただし、Windows 上で動かしてみていないので、実際に動くかどうかは不明。

#!/usr/bin/env perl
use strict;
use warnings;

sub qx2_win {
    my @cmd = @_;

    use IPC::Open3;
    use Symbol qw/gensym/;
    use POSIX ":sys_wait_h";
    use File::Temp qw/tempfile/;

    my $child_out = tempfile();
    my $child_err = tempfile();
    my $pid = open3(undef, '>&'. fileno($child_out), '>&' . fileno($child_err), @cmd);

    while (1) {
        if (waitpid($pid, WNOHANG) > 0) {
            last;
        }
    }

    my $code = WIFEXITED($?) ? WEXITSTATUS($?) : WTERMSIG($?);

    seek $child_out, 0, 0;
    seek $child_err, 0, 0;
    my $out = do { local $/; <$child_out>; };
    my $err = do { local $/; <$child_err>; };

    return ($out, $err, $code);
}

sub qx2 {
    my @cmd = @_;

    use IPC::Open3;
    use Symbol qw/gensym/;
    use IO::Select;
    use POSIX ":sys_wait_h";

    my ($child_out, $child_err) = (gensym, gensym);
    my $pid = open3(undef, $child_out, $child_err, @cmd);

    my $s = new IO::Select($child_out, $child_err);
    my $out = my $err = '';

    while (1) {
        while (my @ready = $s->can_read) {
            for my $fh (@ready) {
                if (sysread($fh, my $buf, 4096) > 0) {
                    if ($fh == $child_out) {
                        $out .= $buf;
                    } elsif ($fh == $child_err) {
                        $err .= $buf;
                    }
                } else {
                    $s->remove($fh);
                    close $fh;
                }
            }
        }

        if (waitpid($pid, WNOHANG) > 0) {
            last;
        }
    }

    my $code = WIFEXITED($?) ? WEXITSTATUS($?) : WTERMSIG($?);
    return ($out, $err, $code);
}

use Test::More;

my @tests = (
    { command => [ 'perl', '-e', q{print 'a'} ], out => 'a', err => '', code => 0 },
    { command => [ 'perl', '-e', q{exit 0} ], out => '', err => '', code => 0 },
    { command => [ 'perl', '-e', q{exit 1} ], out => '', err => '', code => 1 },
    { command => [ 'perl', '-e', q{exit 255} ], out => '', err => '', code => 255 },
    { command => [ 'perl', '-e', q{print 'a' x (1024 ** 2)} ], out => 'a' x (1024 ** 2), err => '', code => 0 },
    { command => [ 'perl', '-e', q{print STDERR 'a' x (1024 ** 2)} ], out => '', err => 'a' x (1024 ** 2), code => 0 },
    { command => [ 'perl', '-e', q{print 'a' x (1024 ** 2); print STDERR 'b' x (1024 ** 2)} ], out => 'a' x (1024 ** 2), err => 'b' x (1024 ** 2), code => 0 },
);


for my $test (@tests) {
    my ($out, $err, $code) = qx2(@{$test->{command}});
    is $out, $test->{out};
    is $err, $test->{err};
    is $code, $test->{code};
}

for my $test (@tests) {
    my ($out, $err, $code) = qx2_win(@{$test->{command}});
    is $out, $test->{out};
    is $err, $test->{err};
    is $code, $test->{code};
}

done_testing;

vim で Tabpage 毎にカレントディレクトリを分ける

ということで、こんなのを .vimrc に追加してみた。

https://github.com/kana/config/blob/master/vim/personal/dot.vimrc 700 行目付近を参考に……。

:TabpageCD を使うようにするのではなく、:cd で行けるように改良してみたつもり。

" per-tab current dir

autocmd! TabEnter *
\ if exists('t:cwd')
\ |   execute 'cd' t:cwd
\ | endif

autocmd! TabLeave * let t:cwd = getcwd()

-Wc++compat

gcc にこんなオプションあるの知らなかった。

試しに付けて↓をコンパイルしてみると、

#include <stdlib.h>

typedef struct hoge {
    int a;
    int b;
} hoge_t;

int main(void)
{
    hoge_t *p = 0;
    p = malloc(sizeof * p);
    free(p);

    return 0;
}
% gcc -Wall -Wextra -Wc++-compat test.c
test.c: In function ‘main’:
test.c:11: warning: request for implicit conversion from ‘void *’ to ‘struct hoge_t *’ not permitted in C++

C++ では、void * は明示的にキャストしないといけないんだった。
最近 C++ 書いてないから忘れちゃいました。というか、C++ で void * はあまり使わない気もするけど。

C++ としてコンパイルすると↓な感じでエラーに。

% g++ -Wall -Wextra test.c
test.c: In function ‘int main()’:
test.c:11: error: invalid conversion from ‘void*’ to ‘hoge_t*’
[1]    10979 exit 1     g++ -Wall -Wextra test.c

twitter sample stream に JSON 以外のデータが混ざって送られてきてる気がする

AnyEvent::Twitter::Stream 0.20 を使って、sample stream を拾って遊んでいるんですが、2011-01-10 辺りから何やらエラーが出るようになってしまっていました。

細かく見ると、どうやら Twitter 側から流れてくるデータに、JSON じゃないものが混ざってしまう現象が起きている模様。とりあえず以下のパッチで回避してみました。

YAPC::Asia 2010 day 2 memo

メモと筆者の私見がまざっています。また、内容に誤りがある可能性がありますので、あしからず。

  • Unix programming with perl
    • errno
    • fork and file handle
      • fd がコピーされるからヤバイ
    • signal
      • wait waitpid と signal の相性

まとめると、C/C++ で書くときに気をつける事を、perl でも気をつけないとねという話だった

  • let's database testing!!
    • DBI でやります
    • テスト環境と DB を同じにしてテスト
    • Test::Fixture
    • Test::mysqld
    • Test::Fixture::DBI
    • Test::mysqld->new を毎回やってたら時間がかかるんで、make test 頭でやるモジュールを
  • Inside LLEval
    • 改め use LLEval;
  • LT
    • top of the 2010
    • opts.pm
      • よさげなオプションパースライブラリ
    • Vim & Perl
    • もっとMySQL
      • MySQLをwebサーバーにしてみたw
    • There Are So Many Ways To Shuffle It
    • ページャー実装マニアックス
    • (by tokuhirom)
      • スライド無し
      • はやいhttpクライアント作ったよという、酔っ払いトーク
    • 岡山.pm / 都会.pm
      • 人があつまらない
    • perl同人誌の宣伝
    • 草 + perl
      • Werl !!!
    • Test::Apache::RewriteRules で mod_rewrite のテストを書こう
    • Facebookを流行らせたのはボクです
      • Library作者だけじゃなく、ユーザーも、Blogを書いて、広げましょう

miyagawa さんのトークは、心が震えた。
Don't ask just do it! とか。
Plack が成功しているのは、最高のプログラマが集まってきているから。


絶望するほど遠い、遥か上を見上げながらも、努力は続けていかないとだなぁ、と思った。

YAPC::Asia 2010 day 1 memo

1日目メモ。本気出してメモとってないので、参考程度で!
主題や発表者が空欄だったりします。すみませんすみません。

  • 体調悪くて昼まで寝てた
  • 東工大に着いてから30分間講堂を探して歩き回った。迷子力はんぱない
  • DataPortability and SocialWeb Protocols - Lyo Kato
    • 各種 protocol 紹介
    • OpenIDPerl なライブラリがなかった→ OpenID::Lite 作った
    • OAuth の説明
      • 2.0 から expire がついた
      • OAuth::Lite 作った
    • OpenID, OAuth は、それぞれ、認証、認可
    • 似てるところもある
    • OpenID と OAuth を連携させる
    • OAuth 2.0
      • SSL必須
      • session, scope の標準化
      • Request Token が無くなった
      • Web 以外での利用も?
    • OAuth::Lite2
      • OAuth2.0 (draft 10)
    • OAuth on native app
  • Studying HTTP with Perl - mala
  • 移動で迷いそうになる
  • 会場を移動したら満員で入れなかったので、WiFi 設定と格闘する
  • LT (以下、本当にうろおぼえメモ)
    • php 書きが perl の会社に入ったら
      • perl に抱いていた印象の話
    • (発表者: そらのさん)
      • 中継の話
    • AnySan (発表者: yappo)
      • AnySan, AnyEventつかったメッセージングサービス
      • スライドにオーバーラップする reply
      • dan_the_bot
    • (発表者: 忍者)
      • 手裏剣選手権に出たらしい
      • 今日のCPANモジュールが本になるらしい
      • 2010/12 on store?
      • よく使われている CPAN モジュールを調べた
      • http://ofpm.koneta.org/
    • MySQL の plugin いろいろ
      • かみぽ持ち
    • 名古屋で perl 勉強会はじめました
      • スライドがドラクエ
    • ruby プログラマphp 開発の会社に入って
    • YAPC::EU 2010 reports
      • YAPC::EUは、たべものがいっぱい
      • DeNA では経費で海外カンファレンスにいける
    • 基幹システムがperlでこうなった
      • OpenCOBOL から MySQL を使いたいという案件
      • OpenCOBOL に perl をつっこんでみた
      • use JCL; ?!!!
      • COBOLperl をつっこんだ副作用でネットワークとかも簡単に使えるようになって、顧客に好評
      • apache + mod_php + OpenCOBOL + perl + MySQL なシステムの完成
    • Test::QUnit
      • JavaScript test
      • MozRepl で test -> QUnit
      • これを prove でたたくライブラリ?
    • T-shirts hack
      • YAPC の T-shirts いっぱい有るけど、サイズが mens で大きい
      • はさみで hack!
    • (発表者: 竹迫さん)
      • alnum なしでプロラミング
      • ascii 10文字だけでプログラミング
      • コンパイルも必要ない!