January 2010

80文字は現代的じゃないから120文字にしようというパッチが投稿


From: Stefani Seibold
Subject: [PATCH] checkpatch.pl: remove the 80 charactes punch card limit

The time of 80 characters punch card and terminals are over, so i would
be a good thing to set the line length limit to 120. Every display today
should be able handle this.

Signed-off-by: Stefani Seibold
---
checkpatch.pl | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

--- linux-2.6.33-rc2.orig/scripts/checkpatch.pl 2009-12-03 04:51:21.000000000 +0100
+++ linux-2.6.33-rc2.new/scripts/checkpatch.pl 2010-01-06 17:46:40.057565661 +0100
@@ -1374,13 +1374,13 @@ sub process {
# check we are in a valid source file if not then ignore this hunk
next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/);

-#80 column limit
+#120 column limit
if ($line =~ /^\+/ && $prevrawline !~ /\/\*\*/ &&
$rawline !~ /^.\s*\*\s*\@$Ident\s/ &&
$line !~ /^\+\s*printk\s*\(\s*(?:KERN_\S+\s*)?"[X\t]*"\s*(?:,|\)\s*;)\s*$/ &&
- $length > 80)
+ $length > 120)
{
- WARN("line over 80 characters\n" . $herecurr);
+ WARN("line over 120 characters\n" . $herecurr);
}

# check for adding lines without a newline.



Andi Kleen登場


> The time of 80 characters punch card and terminals are over, so i would
> be a good thing to set the line length limit to 120. Every display today
> should be able handle this.
>
> Signed-off-by: Stefani Seibold

Full Ack!

-Andi



撃沈


>> The time of 80 characters punch card and terminals are over, so i would
>> be a good thing to set the line length limit to 120. Every display today
>> should be able handle this.
>>
>> Signed-off-by: Stefani Seibold
>
> Full Ack!
>
NACK Attack!

There is a reason Knuth only put so many words on a line with TeX.

Eugh.

Cheers



やはり140文字にしなかったのが敗因か ← ちがいます

Knuthのくだりは何がいいたいのかよく分からんかった
どうでもいいけど、マジメに議論する気がないのがヒシヒシと伝わってくるいいメールだな。お互いに
このエントリーをはてなブックマークに追加

中身はまったく把握してないが、akrさんが巨大なドライバパッチ(3000行越え!)を-mmにねじ込んだようだ。
(From行に注目)

すごいなー


The patch titled
SIS USB2VGA DRIVER: support KAIREN's USB VGA adaptor USB20SVGA-MB-PLUS
has been added to the -mm tree. Its filename is
sis-usb2vga-driver-support-kairens-usb-vga-adaptor-usb20svga-mb-plus.patch

Before you just go and hit "reply", please:
a) Consider who else should be cc'ed
b) Prefer to cc a suitable mailing list as well
c) Ideally: find the original patch on the mailing list and do a
reply-to-all to that, adding suitable additional cc's

*** Remember to use Documentation/SubmitChecklist when testing your code ***

See http://userweb.kernel.org/~akpm/stuff/added-to-mm.txt to find
out what to do about this

The current -mm tree may be found at http://userweb.kernel.org/~akpm/mmotm/

------------------------------------------------------
Subject: SIS USB2VGA DRIVER: support KAIREN's USB VGA adaptor USB20SVGA-MB-PLUS
From: Tanaka Akira <akr _at_ fsij.org>

Add the USB product ID of KAIREN's USB VGA Adaptor, USB20SVGA-MB-PLUS, to
make sisusbvga work with it.

Signed-off-by: Tanaka Akira <akr _at_ fsij.org>
Cc: Thomas Winischhofer <thomas@winischhofer.net>
Cc: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---

drivers/usb/misc/sisusbvga/sisusb.c | 1
drivers/usb/misc/sisusbvga/sisusb.c.orig | 3293 +++++++++++++++++++++
2 files changed, 3294 insertions(+)

(略)

このエントリーをはてなブックマークに追加

なんてものが、LKMLに投稿されているな


Date: Wed, 20 Jan 2010 02:02:02 +0000
From: Ben Dooks
To: linux-arm-kernel@lists.infradead.org,
Linux Samsung SoC ,
Linux Kernel
Subject: git pre-commit hook running checkpatch.pl

I've written a git pre-commit[1] hook which stops any commits happening if
checkpatch.pl reports problems with the patch. Any comments?

[1] http://www.fluff.org/ben/linux/githooks/pre-commit

--
Ben

Q: What's a light-year?
A: One-third less calories than a regular year.



リンク切れに備えて、直接はっておこう

#!/bin/sh
#
# pre-commit hook to run check-patch on the output and stop any commits
# that do not pass. Note, only for git-commit, and not for any of the
# other scenarios
#
# Copyright 2010 Ben Dooks,

if git rev-parse --verify HEAD 2>/dev/null >/dev/null
then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

git diff --cached $against -- | ./scripts/checkpatch.pl --no-signoff -


このエントリーをはてなブックマークに追加

ひさしぶりにプログラミングの話題でも。
現在のRubyのtrunkをx86_64上のFedora12でmake test-allすると8個ぐらいテストが失敗するのだが、その中の1つにこういうエラーがある

  1) Failure:
test_sin(DL::TestDL) [/home/kosaki/linux/ruby/test/dl/test_dl2.rb:95]:
<1.0> expected but was
<1.38523885234213e-309>.


test/dl/test_dl2.rbというのが、なにをしているテストかというと、ようするに以下のようにdlモジュールを使ってlibmのsin関数を呼んでいるわけだ

module DL
class TestDL < TestBase
# TODO: refactor test repetition
def test_sin()
pi_2 = Math::PI/2
cfunc = CFunc.new(@libm['sin'], TYPE_DOUBLE, 'sin')
x = cfunc.call([pi_2].pack("d").unpack("l!*"))
assert_equal(Math.sin(pi_2), x)
end
end
end # module DL


dlモジュールというのは(僕は知らなかったのだが)RubyからCのコードを直接呼ぶためのしくみで、引数をpackとunpackを使ってlongの配列にしておくと、なぜか関数の型に関わらず正しい結果がかえって来るという魔法のライブラリである。

まあ sin(π/2)が1.0にならなかったら、バグだよね。


では、その実装をみていこう


static VALUE
rb_dlcfunc_call(VALUE self, VALUE ary)
{
struct cfunc_data *cfunc;
int i;
DLSTACK_TYPE stack[DLSTACK_SIZE];
VALUE result = Qnil;

rb_secure_update(self);

memset(stack, 0, sizeof(DLSTACK_TYPE) * DLSTACK_SIZE);
Check_Type(ary, T_ARRAY);

TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);

if( cfunc->ptr == 0 ){
rb_raise(rb_eDLError, "can't call null-function");
return Qnil;
}

for( i = 0; i < RARRAY_LEN(ary); i++ ){
if( i >= DLSTACK_SIZE ){
rb_raise(rb_eDLError, "too many arguments (stack overflow)");
}
rb_check_safe_obj(RARRAY_PTR(ary)[i]);
stack[i] = NUM2LONG(RARRAY_PTR(ary)[i]);
}


まず、RubyのArray(ary)をCのArray(stack[])に変換する。


switch( cfunc->type ){
case DLTYPE_VOID:
#define CASE(n) case n: { \
DECL_FUNC_CDECL(f,void,DLSTACK_PROTO##n) = cfunc->ptr; \
f(DLSTACK_ARGS##n(stack)); \
result = Qnil; \
}
CALL_CASE;
#undef CASE
break;
・・・

case DLTYPE_DOUBLE:
#define CASE(n) case n: { \
DECL_FUNC_CDECL(f,double,DLSTACK_PROTO##n) = cfunc->ptr; \
double ret; \
ret = f(DLSTACK_ARGS##n(stack)); \
result = rb_float_new(ret); \
}
CALL_CASE;
#undef CASE


んで、CFunc.newで渡したtypeに応じてクソ長い switch caseが始まる。ここでさらに引数の数に応じて場合分けしたいが最大引数数がrubyのdlモジュールの仕様上20個もあるため、いちいち書くのがめんどくさいのでCASE, CALLCASEマクロで量産している。CALL_CASEマクロの定義は以下


#define CALL_CASE switch( RARRAY_LEN(ary) ){ \
CASE(0); break; \
CASE(1); break; CASE(2); break; CASE(3); break; CASE(4); break; CASE(5); break; \
CASE(6); break; CASE(7); break; CASE(8); break; CASE(9); break; CASE(10);break; \
CASE(11);break; CASE(12);break; CASE(13);break; CASE(14);break; CASE(15);break; \
CASE(16);break; CASE(17);break; CASE(18);break; CASE(19);break; CASE(20);break; \
default: rb_raise(rb_eArgError, "too many arguments"); \
}


というわけで、cfunc.call()すると


DECL_FUNC_CDECL(f,double,DLSTACK_PROTO##n) = cfunc->ptr; \


はCFunc.newでlookupした関数ポインタcfunc->ptr(この場合はsin())をfに代入して、


double ret; \
ret = f(DLSTACK_ARGS##n(stack)); \


fをcallして


result = rb_float_new(ret); \


それをrubyのfloatオブジェクトに変換して返す。ということをしているのだと分かる。実装の詳細を見るために
DLSTACK_PROTO1
DECL_FUNC_CDECL
DLSTACK_ARGS1
のマクロ定義も見ていこう。(あ、今回は引数1つなので##nは1になる。CALL_CASEマクロをもう一度みると納得できると思います。)

まず、DLSTACK_PROTO1とDECL_FUNC_CDECLから見る

#define DLSTACK_TYPE long
#define DLSTACK_PROTO1_ DLSTACK_TYPE
#define DLSTACK_PROTO1 DLSTACK_PROTO1_, ...

#if !defined(FUNC_CDECL)
# define FUNC_CDECL(x) x
#endif
# define DECL_FUNC_CDECL(f,ret,args) ret (FUNC_CDECL(*f))(args)


ようするに DLSTACK_PROTO1 → "long, ..." で結果として

DECL_FUNC_CDECL(f,double,DLSTACK_PROTO##n) = cfunc->ptr; \

という行は

double (*f)(long, ...) = cfunc->ptr;

となる。

わざわざ可変長引数にしている理由は、すぐそばに以下のコメントががが

/*
* Add ",..." as the last argument.
* This is required for variable argument functions such
* as fprintf() on x86_64-linux.
*
* http://refspecs.linuxfoundation.org/elf/x86_64-abi-0.95.pdf
* page 19:
*
* For calls that may call functions that use varargs or stdargs
* (prototype-less calls or calls to functions containing ellipsis
* (...) in the declaration) %al is used as hidden argument to
* specify the number of SSE registers used.
*/


つまり、x86_64では...を特別扱いするから、これでうまくいくんだよ。と言いたいようだ。

でもって、DLSTACK_ARGS1は


#define DLSTACK_ARGS1(stack) stack[0]


なので、

f(DLSTACK_ARGS##n(stack)); \



f(stack[0]);

という普通の関数呼び出しになる。

あれ?なんかx86_64対策も入ってるのになんでうまくいかんのだ?という話になるので、参照されているx86_64 ABI
の原典を読む



3.2.3 Parameter Passing

After the argument values have been computed, they are placed in registers, or
pushed on the stack. The way how values are passed is described in the following
sections.

Definitions We first define a number of classes to classify arguments. The
classes are corresponding to AMD64 register classes and defined as:

INTEGER This class consists of integral types that fit into one of the general
purpose registers.
SSE The class consists of types that fits into a SSE register.
SSEUP The class consists of types that fit into a SSE register and can be passed
and returned in the most significant half of it.
X87, X87UP These classes consists of types that will be returned via the x87 FPU.
COMPLEX_X87 This class consists of types that will be returned via the x87 FPU.
NO_CLASS This class is used as initializer in the algorithms. It will be used for
padding and empty structures and unions.
MEMORY This class consists of types that will be passed and returned in memory
via the stack.


超訳。ABI的にはINTEGER, SSE, SSEUP, X87, X87UP, COMPLEX_X87, NO_CLASSという
引数のタイプがあるよ。



Classification The size of each argument gets rounded up to eightbytes.
The basic types are assigned their natural classes:

• Arguments of types (signed and unsigned) _Bool, char, short, int,
long, long long, and pointers are in the INTEGER class.
• Arguments of types float, double and __m64 are in class SSE.
(しばらく略)


超訳
(signed and unsigned) _Bool, char, short, int, long, long long, およびポインタは INTEGERだよ
float, double and __m64 はSSEだよ

(この後、__float128とか構造体とかの説明がつづくが割愛)



Passing Once arguments are classified, the registers get assigned (in left-to-right
order) for passing as follows:

1. If the class is MEMORY, pass the argument on the stack.
2. If the class is INTEGER, the next available register of the sequence %rdi,
%rsi, %rdx, %rcx, %r8 and %r9 is used.
3. If the class is SSE, the next available SSE register is used, the registers are
taken in the order from %xmm0 to %xmm7.
4. (略)
5. (略)


超訳。
MEMORYならスタック渡し確定
INTEGERならrdi, rsi, rdx, rcx, r8, r9の順に使うよ
SSEならSSEレジスタをxmm0からxmm7の順につかうよ


If there is no register available anymore for any eightbyte of an argument, the
whole argument is passed on the stack. If registers have already been assigned for
some eightbytes of this argument, those assignments get reverted.

Once registers are assigned, the arguments passed in memory are pushed on
the stack in reversed (right-to-left) order.


超訳
レジスタが足りなくなったらスタックを使って引数を渡すよ。
スタックには逆順(右から左)でpushするよ


で、ここで問題のセンテンスが現れる

For calls that may call functions that use varargs or stdargs (prototype-less
calls or calls to functions containing ellipsis (. . . ) in the declaration) %al is used
as hidden argument to specify the number of SSE registers used. The contents of
%al do not need to match exactly the number of registers, but must be an upper


超訳
varargsまたはstdargsな関数(プロトタイプがなかったり、宣言で...を使っていたり)を呼ぶときは
%al に何個SSEレジスタを使ったか隠し引数で入れるよ。


つまり、ここではprintf()的なまっとうな可変長引数の事を語っているだけであって、呼び出し元と呼び出し先で
関数の型が適合しない場合については何も語っていない。

今回の場合で言うとsin関数はlibmの中では
double sin(double)
という型でコンパイルされていて、呼び出し側では
double f(long, ...)
という型だと思ってcallしている。

じゃあ、実際に何が起こるかを示すためにテストプログラムを書いてみた。

main.c

#define _GNU_SOURCE
#include
#include

void f1(void) {
double (*func)(long, ...);
double d = 57.0;
long l = *(long*)&d;
double ret;

func = dlsym(RTLD_DEFAULT, "func");
ret = func(l);
printf("%f\n",ret);
}

int main(void)
{
f1();
return 0;
}


f.c

double func(double d)
{
return d*2;
}


実行結果

% gcc *.c -ldl -Wall -g -rdynamic; ./a.out
0.000000


はい、57*2で114 が返ってくるはずが0が返ってきてしまいました。

んではdisassemble,


0000000000400834 :
400834: 55 push %rbp
400835: 48 89 e5 mov %rsp,%rbp
400838: f2 0f 11 45 f8 movsd %xmm0,-0x8(%rbp)
40083d: f2 0f 10 45 f8 movsd -0x8(%rbp),%xmm0
400842: f2 0f 58 c0 addsd %xmm0,%xmm0
400846: c9 leaveq
400847: c3 retq


funcでは素直にxmm0を引数だと思って二倍しています。


00000000004008e0 :
4008e0: 55 push %rbp
4008e1: 48 89 e5 mov %rsp,%rbp
4008e4: 48 83 ec 20 sub $0x20,%rsp
4008e8: 48 b8 00 00 00 00 00 mov $0x404c800000000000,%rax
4008ef: 80 4c 40
4008f2: 48 89 45 e0 mov %rax,-0x20(%rbp)
4008f6: 48 8d 45 e0 lea -0x20(%rbp),%rax
4008fa: 48 8b 00 mov (%rax),%rax
4008fd: 48 89 45 f0 mov %rax,-0x10(%rbp)
400901: b8 48 0b 40 00 mov $0x400b48,%eax
400906: 48 89 c6 mov %rax,%rsi
400909: bf 00 00 00 00 mov $0x0,%edi
40090e: e8 2d fe ff ff callq 400740
400913: 48 89 45 e8 mov %rax,-0x18(%rbp)
400917: 48 8b 45 f0 mov -0x10(%rbp),%rax
40091b: 48 8b 55 e8 mov -0x18(%rbp),%rdx
40091f: 48 89 c7 mov %rax,%rdi
400922: b8 00 00 00 00 mov $0x0,%eax
400927: ff d2 callq *%rdx
400929: f2 0f 11 45 f8 movsd %xmm0,-0x8(%rbp)
40092e: b8 4d 0b 40 00 mov $0x400b4d,%eax
400933: f2 0f 10 45 f8 movsd -0x8(%rbp),%xmm0
400938: 48 89 c7 mov %rax,%rdi
40093b: b8 01 00 00 00 mov $0x1,%eax
400940: e8 db fd ff ff callq 400720
400945: c9 leaveq
400946: c3


でもf1ではrdi(INTEGERの第一引数)に l を、eaxに0を入れて関数コールしています。

つまり、これが起きていることのすべてです。
呼び出し側がrdiに引数を詰んでいるのに、呼び出され側はxmm0を呼んでいるのですから
正しい答えが返るはずがありません。

というわけで、これはdlモジュール制作者のABIの誤読ですね。
なお、Cの規格的には呼び出し元と呼び出し先で関数型が適合しない場合は未定義。たぶん、dlモジュール作者は規格を元に考えたのではなく

1)全CPUアーキテクチャでlongで無理矢理callしても安心と考えた。または
2)x86_32 だけで動けばいいや。と割り切った

のどちらかだと思いますが、イマドキx86_64は普通ですからねぇ。。。

現在のインターフェースだと直しようがないので、RubyのCFuncの仕様を大きく変えないと x86_64対応は出来ないでしょう。
というわけで、RubyユーザのみなさんはCFuncでfloat, doubleを使わないようにしておくと将来幸せになれるかもしれないというお話でした。

ではでは


追記: なぜこの問題がx86_64だけで発生するのかを、つらつらと考えてみたのだが、やはり歴史的な理由だろう。昔は関数宣言を忘れるとか当たり前だったので、昔からあるアーキだと、こういう関数型が不適合な呼び出しに対してABIを寛容に作ることが多かったのではないか?

追記2: 関数の型の適合性とか安易に書いた気がする。でもCの規格を読み直す気がおきない。めどい
簡単にいうと
1)呼び出し元と呼び出し先が両方とも関数宣言有り: 引数、戻り値の型が全部一致していた場合のみOK
2)どちらかが宣言なし: 戻り値の型は厳密一致が必要だけど、引数は型がshortとintみたいに十分近ければOK
みたいなノリだったと思う。今回はケース1だけど、2の基準で反転してもアウトという論外さ
このエントリーをはてなブックマークに追加

公開されたようです。
執筆用の実験で、snap-shot mergeした領域をディストリ付属の古いLVMツールで触ってしまい
(とゆーか、OS起動時に勝手に触るんだが)
ストレージを壊してしまいさんざんでした。ほむり

http://www.atmarkit.co.jp/flinux/rensai/watch2009/watch12a.html
このエントリーをはてなブックマークに追加

某所でrubyのDTrace対応をしていたので、「ついでじゃないか」理論でsystemtap対応をプッシュしてみた。Fedora12のSystemTapのuser space probeが腐っていて共有ライブラリにprobe入れると動かないので回避方法探すのに苦労したがなんとか動いた。
このフィードバックをもとに、近いうちにFrankをDisる回を開催する予定。
このエントリーをはてなブックマークに追加

↑このページのトップヘ