PTHREAD_STACK_MIN宏指示一个线程堆栈的最小字节。当调用pthread_attr_setstacksize()函数设定线程堆栈时,设定的线程堆栈大小值必须大于等于PTHREAD_STACK_MIN宏定义的值,否则返回错误。

不同的处理器和操作系统,PTHREAD_STACK_MIN宏具有不同值,这也是该宏存在的意义。它一般定义在limits.h头文件中。不过,也有例外。

问题现象

在博通(broadcom)MIPS平台上开发多线程程序时就发现了这个例外。只要线程一旦开始运行就会出现段错误(segment fault)。经过分析,估计是设置的线程堆栈太小导致的。问题是,程序里设置线程堆栈大小值为PTHREAD_STACK_MIN,这怎么可能出错呢?

再仔细分析发现,原来程序里对这个宏有个额外的定义,如下代码所示:

#include <limits.h>

#ifdef _CYGWIN__
   #ifndef PTHREAD_STACK_MIN
   #warning "!Undefine PTHREAD_STACK_MIN, use the custom value 8192!"
   #define PTHREAD_STACK_MIN  8192
   #endif
#else
   #ifndef PTHREAD_STACK_MIN
   #warning "!Undefine PTHREAD_STACK_MIN, use the custom value 16384!"
   #define PTHREAD_STACK_MIN 16384
   #endif
#endif

然后,在程序里,把PTHREAD_STACK_MIN宏值打印出来,结果为16384。也就是说,在limits.h头文件中没有该宏的定义。

这是怎么回事?

问题分析

首先,我检索下交叉编译器里倒底有木有宏PTHREAD_STACK_MIN的定义,如下所示:

$ grep -r “PTHREAD_STACK_MIN” ./
匹配到二进制文件 ./mipsel-unknown-linux-gnu/bin/getconf
./mipsel-unknown-linux-gnu/include/bits/local_lim.h:#define PTHREAD_STACK_MIN 131072
grep: 警告: ./mipsel-unknown-linux-gnu/include/include: 嵌套目录循环

./mipsel-unknown-linux-gnu/include/pthread.h: minimal size of the block must be PTHREAD_STACK_MIN. */
./mipsel-unknown-linux-gnu/include/pthread.h: to be started. This size must never be less than PTHREAD_STACK_MIN
./mipsel-unknown-linux-gnu/usr/include/bits/local_lim.h:#define PTHREAD_STACK_MIN 131072
grep: 警告: ./mipsel-unknown-linux-gnu/usr/include/include: 嵌套目录循环

./mipsel-unknown-linux-gnu/usr/include/pthread.h: minimal size of the block must be PTHREAD_STACK_MIN. */
./mipsel-unknown-linux-gnu/usr/include/pthread.h: to be started. This size must never be less than PTHREAD_STACK_MIN
./usr/include/bits/local_lim.h:#define PTHREAD_STACK_MIN 131072
grep: 警告: ./usr/include/include: 嵌套目录循环

./usr/include/pthread.h: minimal size of the block must be PTHREAD_STACK_MIN. */
./usr/include/pthread.h: to be started. This size must never be less than PTHREAD_STACK_MIN

经过检索发现,mips交叉编译器里有宏PTHREAD_STACK_MIN的定义(打红色的地方),不过,它不是位于limits.h头文件中,而是位于bits/local_lim.h头文件下。

现在的问题是:limits.h头文件中有没有直接或间接包含bits/local_lim.h头文件?

再次检索发现,mips交叉编译器的多个路径下都有limits.h头文件,如下所示:

$ find -name limits.h
./lib/gcc/mipsel-unknown-linux-gnu/4.4.6/include-fixed/limits.h
./lib/gcc/mipsel-unknown-linux-gnu/4.4.6/install-tools/include/limits.h
./lib/gcc/mipsel-unknown-linux-gnu/4.5.3/include-fixed/limits.h
./lib/gcc/mipsel-unknown-linux-gnu/4.5.3/install-tools/include/limits.h
./mipsel-unknown-linux-gnu/include/c++/4.4.6/tr1/limits.h
./mipsel-unknown-linux-gnu/include/c++/4.5.3/tr1/limits.h
./mipsel-unknown-linux-gnu/include/limits.h
./mipsel-unknown-linux-gnu/include/linux/limits.h

使用命令:mipsel-unknown-linux-gnu-gcc –v,可查看到交叉编译器使用的版本为4.4.6,所以可以排除4.5.3路径下的limits.h头文件。

深入分析后,发现只有./lib/gcc/mipsel-unknown-linux-gnu/4.4.6/include-fixed/limits.h头文件间接包含了bits/local_lim.h头文件。

分析到这里,问题的根本应该是:交叉编译应用程序时,使用的是哪个limits.h头文件了。这也是本文要重点说明的内容。

头文件路径

我们知道,在应用程序里,可以使用-I选项来指定包含目录的路径。实际上,编译程序时,编译器会指定默认的头文件搜索路径的。可使用命令:arm-linux-gcc -E -v -”来查看。如下所示。

$ mipsel-unknown-linux-gnu-gcc -E -v –
Using built-in specs.
Target: mipsel-unknown-linux-gnu
Configured with: ../configure –target=mipsel-unknown-linux-gnu –prefix=/cross-root –enable-clocale=gnu –enable-threads=posix –enable-__cxa_atexit –enable-c99 –enable-long-long –disable-libstdcxx-pch –disable-libunwind-excaptions –disable-nls –enable-shared –disable-multilib –enable-languages=c,c++ –with-gmp=/build-temp –with-mpfr=/build-temp –with-mpc=/build-temp
Thread model: posix
gcc version 4.4.6 (GCC)
COLLECT_GCC_OPTIONS=’-E’ ‘-v’ ‘-mllsc’ ‘-mno-shared’
/cross-root/libexec/gcc/mipsel-unknown-linux-gnu/4.4.6/cc1.exe -E -quiet -v – -mllsc -mno-shared
ignoring nonexistent directory “/cross-root/lib/gcc/mipsel-unknown-linux-gnu/4.4.6/../../../../mipsel-unknown-linux-gnu/sys-include”
#include “…” search starts here:
#include <…> search starts here:
/cross-root/lib/gcc/mipsel-unknown-linux-gnu/4.4.6/include
/cross-root/lib/gcc/mipsel-unknown-linux-gnu/4.4.6/include-fixed /cross-root/lib/gcc/mipsel-unknown-linux-gnu/4.4.6/../../../../mipsel-unknown-linux-gnu/include
End of search list.

其中,

#include “…” search starts here:
#include <…> search starts here:
/cross-root/lib/gcc/mipsel-unknown-linux-gnu/4.4.6/include
/cross-root/lib/gcc/mipsel-unknown-linux-gnu/4.4.6/include-fixed /cross-root/lib/gcc/mipsel-unknown-linux-gnu/4.4.6/../../../../mipsel-unknown-linux-gnu/include
End of search list.

这一段指定了编译器默认的头文件搜索路径,共有3个搜索路径,具有不同的搜索顺序。具体来说是:当使用#include <filename.h>包含头文件时,首先会去上面的第一个路径搜索,如果找到则停止搜索,如果没找到,则去第二路径搜索。如果第三个搜索路径下依旧没有找到头文件,编译器则会报错。

使用类似方法,可以查看其它(交叉)编译器默认的头文件搜索路径。

#include_next

在分析PTHREAD_STACK_MIN宏定义所在位置时,在syslimits.h文件中发现了如下的头文件包含:

#define _GCC_NEXT_LIMITS_H		/* tell gcc's limits.h to recurse */
#include_next <limits.h>
#undef _GCC_NEXT_LIMITS_H

#include_next,这是什么?

#include_next是GNU的一个扩展,不是标准C中的指令。个人对它的理解是:去下一个头文件搜索路径下搜索头文件。

参考资料

  1. gcc:预处理语句--#include和#include_next:http://blog.csdn.net/fjb2080/article/details/5247494
  2. 关于头文件的问题:http://blog.chinaunix.net/uid-29145190-id-3867605.html
» 文章出处: reille博客—http://velep.com , 如果没有特别声明,文章均为reille博客原创作品
» 郑重声明: 原创作品未经允许不得转载,如需转载请联系reille#qq.com(#换成@)
分享到:

 Leave a Reply

(必须)

(我会替您保密的)(必须)

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.

   
© 2012 velep.com | reille blog | 管理| 粤ICP备15065318号-2| 谷歌地图| 百度地图| Suffusion theme|Sayontan Sinha

无觅相关文章插件,快速提升流量