Linux 内核使用的 GNU C 扩展
时间:2006-07-20 来源:zqy2000zqy
|
||
From:www.linuxforum.net
如有错误或遗漏,欢迎指正。
补充几个从CLF看来的GCC知识(GCC之外的工具), 对某些内核代码的理解有帮助:P Q: 请问:__attribute__((nocast))??? __attribute__((nocast))是个什么意思?查了 gcc 手册也没有解说! A:(by tclwp) 这个不是gcc做的事在编译内核时, 配置完后 make C=1 或 make C=2 就会调用外部程序sparse (CHECKER)做检查 (有多种选择,自己安装) 还是来看看Linus Torvalds在演讲会上的说明: ......................... Basically you can add attributes to any kind of data type. In Sparse one of the attributes on data types is which address space it belongs to. This is a define that goes away if you don't use Sparse. So GCC, who doesn't know anything about address spaces, will never see any other code. So GCC treats the exact same code as it always used to do; but when you run it with a Sparse checker, it will notice that when you do a copy_to_user call, the first argument has to be a user pointer. Well, address_space (1), the tool itself doesn't really care about user or kernel; you can use it for anything. If it gets anything that isn't a user pointer, for example, if you switch the arguments around by mistake, which has happened, it will complain with a big fat warning saying "Hey, the address spaces don't match." .................. Q:请问:__context__()是什么意思? A:(by tclwp) _context__(1) add a "+1" context marker 用于代码的静态上下文匹配检查(由CHECKER检查, 见代码中 "#ifdef __CHECKER__") 也可用于自旋锁lock 和 unlock的匹配检查还是看看Linus Torvalds 自己的说明 Make context count warning be controllable with "-Wcontext" flag. (http://www.ussg.iu.edu/hypermail/linux/kernel/0410.3/2846.html) Sparse "context" checking.. From: Linus Torvalds Date: Sat Oct 30 2004 - 22:23:19 EST Next message: OGAWA Hirofumi: "Re: [2.6 patch] kill fatfs_syms.c" Previous message: Andi Kleen: "Re: [PATCH] Add panic blinking to 2.6" Next in thread: Roland Dreier: "Re: Sparse "context" checking.." Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] -------------------------------------------------------------------------------- I just committed the patches to the kernel to start supporting a new automated correctness check that I added to sparse: the counting of static "code context" information. The sparse infrastructure is pretty agnostic, and you can count pretty much anything you want, but it's designed to test that the entry and exit contexts match, and that no path through a function is ever entered with conflicting contexts. In particular, this is designed for doing things like matching up a "lock" with the pairing "unlock", and right now that's exactly what the code does: it makes each spinlock count as "+1" in the context, and each spinunlock count as "-1", and then hopefully it should all add up. It doesn't always, of course. Since it's a purely static analyser, it's unhappy about code like int fn(arg) { if (arg) spin_lock(lock); ... if (arg) spin_unlock(lock); } because the code is not statically deterministic, and the stuff in between can be called with or without a lock held. That said, this has long been frowned upon, and there aren't that many cases where it happens. Right now the counting is only enabled if you use sparse, and add the "-Wcontext" flag to the sparse command line by hand - and the spinlocks have only been annotated for the SMP case, so right now it only works for CONFIG_SMP. Details, details. Also, since sparse does purely local decisions, if you actually _intend_ to grab a lock in one function and release it in another, you need to tell sparse so, by annotating the function that acquires the lock (with "__acquires(lockname)") and the function that releases it (with, surprise surprise, "__releases(lockname)") in the declaration. That tells sparse to update the context in the callers appropriately, but it also tells sparse to expect the proper entry/exit contexts for the annotated functions themselves. I haven't done the annotation for any functions yet, so expect warnings. If you do a checking run, the warnings will look something like: CHECK kernel/resource.c kernel/resource.c:59:13: warning: context imbalance in 'r_start' - wrong count at exit kernel/resource.c:69:13: warning: context imbalance in 'r_stop' - unexpected unlock which just shows that "r_start" acquired a lock, and sparse didn't expect it to, while "r_stop" released a lock that sparse hadn't realized it had. In this case, the cause is pretty obvious, and the annotations are equally so. A more complicated case is CHECK kernel/sys.c kernel/sys.c:465:2: warning: context imbalance in 'sys_reboot' - different lock contexts for basic block where that "different lock contexts" warning means that sparse determined that some code in that function was reachable with two different lock contexts. In this case it's actually harmless, since what happens in this case is that the code after rebooting the machine is unreachable, and sparse just doesn't understand that. But in other cases it's more fundamental, and the lock imbalance is due to dynamic data that sparse just can't understand. The warning in that case can be disabled by hand, but there doesn't seem to be that many of them. A full kernel build for me has about 200 warnings, and most of them seem to be the benign kind (ie the kind above where one function acquires the lock and another releases it, and they just haven't been annotated as such). The sparse thing could be extended to _any_ context that wants pairing, and I just wanted to let people know about this in case they find it interesting.. Linus -------------------------------------------------------------------------------------------------------- Linus> In particular, this is designed for doing things like Linus> matching up a "lock" with the pairing "unlock", and right Linus> now that's exactly what the code does: it makes each Linus> spinlock count as "+1" in the context, and each spinunlock Linus> count as "-1", and then hopefully it should all add up. Do you have a plan for how to handle functions like spin_trylock()? I notice in the current tree you just didn't annotate spin_trylock(). Thanks, Roland -------------------------------------------------------------------------------- On Sat, 30 Oct 2004, Roland Dreier wrote: > > Linus> In particular, this is designed for doing things like > Linus> matching up a "lock" with the pairing "unlock", and right > Linus> now that's exactly what the code does: it makes each > Linus> spinlock count as "+1" in the context, and each spinunlock > Linus> count as "-1", and then hopefully it should all add up. > > Do you have a plan for how to handle functions like spin_trylock()? I > notice in the current tree you just didn't annotate spin_trylock(). Actually, the _current_ tree does actually annotate spin_trylock() (as of just before I sent out the email). It looks like #define spin_trylock(lock) __cond_lock(_spin_trylock(lock)) where __cond_lock() for sparse is include/linux/compiler.h:# define __cond_lock(x) ((x) ? ({ __context__(1); 1; }) : 0) ie we add a "+1" context marker for the success case. NOTE! This works with sparse only because sparse does immediate constant folding, so if you do if (spin_trylock(lock)) { .. spin_unlock(lock); } sparse linearizes that the right way unconditionally, and even though there is a data-dependency, the data depenency is constant. However, if some code does success = spin_trylock(lock); if (success) { .. spin_unlock(lock); } sparse would complain about it, because sparse doesn't do any _real_ data flow analysis. So sparse can follow all the obvious cases, including trylock and "atomic_dec_and_lock()". Linus
摘自:inuxforum |