コーディングサンドボックスを自作する

Wandboxとか、実行くんとか、ideoneでおなじみの即席実行環境を適当に作る。

言語はhtml5(css3)+jquery+php+ruby。

20160606sandbox00.jpg


最終目標はAtcoderやらyukicoderやらcodeIQやらのジャッジシステム。

テストケース作成画面はだいたい出来てる。珍しく完成形が見えてきた。



プログラムを書くときにタメになった事を幾つか書いていく。


unixコマンド呼び出し


実行環境はWindows10のIISだったりする。

Windows版gccを入れるつもりは無かったので、この辺のコンパイル・実行環境はcygwinに投げることにした。

方法は簡単で、cygwinのパスを通すだけ。windowsなのにlsが呼び出せるようになる。


header('Content-Type: text/plain');

putenv("PATH=C:/cygwin64/bin");

$process = proc_open('ls',array(
0=>array("pipe","r"),
1=>array("pipe","w"),
2=>array("pipe","w")), $pipes);

if (is_resource($process)) {
echo stream_get_contents($pipes[1]);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);
echo "ok.";
}else{
echo "ng";
}



タイムアウト


かなりの厄介者だった。

応答プログラムと、タイムアウト計測プログラムは別プロセスの方が良いかな、となんとなく思った。

phpはよく理解できてない事も多かったので、タイムアウト計測はrubyで書いた。rubyにはtimeoutモジュールがある。


popenかexecをtimeoutで括ればいいやろーと軽々しく考えていたのですが、甘くなかった。

C 言語レベルで実装され、 Ruby のスレッドが割り込めない処理に対して timeout は無力です。



pipeで入出力を待つとブロックしてしまい、timeoutが効かなくなってしまうので、外部ファイルを標準入出力にしなければならない。ramdiskを指定すれば良いだけなんだけれども。

色々試行錯誤した結果、かなり汚いプログラムになってしまった。
その方法とは、spawn()でプロセスを作成し、timeout内部でノンブロッキングなwaitpid2で生きているかどうか常に監視し続けること。

sleepを使ってしまっているので、細かい時間計測ができなくなった。僕は特に必要としていなかったけれども。


#rubyちゃん
tictoc=nil
begin
pid=nil
status=nil

pid=spawn(@progcmd+" < "+@stdinpath, :out => ["stdout.txt","w"],:err => ["stderr.txt","w"])

timeout(@timelimit){
tictoc = Benchmark.realtime{
r=nil
loop{
r = Process.waitpid2(pid,Process::WNOHANG)
break if r
sleep 0.02
}
status = r[1] >> 8
}
}

rescue Timeout::Error
Process.kill('SIGINT',pid)
else
ensure
end





2016/08/07追記:

http://docs.ruby-lang.org/ja/2.3.0/class/Timeout.html
サンプル通り記述したら、うまく行った。前は何がダメだったんだろう。


require 'timeout'
require 'benchmark'
begin
pid = nil
com = nil
result = nil
tictoc = Benchmark.realtime{
Timeout.timeout(3) {
com = IO.popen("ruby act.rb",{:err=>["err.log","w"]})
pid = com.pid
result = com.read
}
}
puts result
puts sprintf("time:%5.2f",tictoc)
rescue Timeout::Error => err
puts "timeout: shell execution."
Process.kill('SIGINT', pid)
printf "[result]\t%s", com.read
com.close unless com.nil?
end



2016/11/22 追記

sleepで待機するプログラムは停止しますが、無限ループに落ちたようなプログラムはうまく行かないみたいです。
別の記事でタイムアウト処理についてもう一度書き直します。
スポンサーサイト

テーマ : プログラミング
ジャンル : コンピュータ

コメントの投稿

非公開コメント

プロフィール

舞葉(ぶよう)

Author:舞葉(ぶよう)
github.io
はてなブログ(競プロ)

古い記事のソースコードは色分けしていないので、高機能テキストエディタに貼り付けたほうが見やすいかも。

検索フォーム
このブログについて
自分がつまづいた話題、なんとなく書きたいと思ったこと、ググったけど殆ど資料なかったぞオイ な話等をアップする予定。通りすがりでも、参考になっていただければと。プログラムの例外入力、メモリリークは責任負いません。投稿された記事は修正・削除する場合があります。
カテゴリ
タグ

HSP3アルゴリズムとデータ構造c++RubyJavaUnity画像解析C機械学習C#LinuxcodeIQKinectMinecraftTonyuSystemraspberrypiPythonHTML5音声制御Simulinkruby俺ルール通信制御Javascriptシミュレーション

counter-shinobi
固定記事
最新記事
最新コメント
月別アーカイブ
ブロとも申請フォーム

この人とブロともになる

アクセスランキング
[ジャンルランキング]
コンピュータ
1276位
アクセスランキングを見る>>

[サブジャンルランキング]
プログラミング
225位
アクセスランキングを見る>>