龍芯(MIPS64)平臺線程棧設置出錯之調試過程

###線程測試代碼

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>

void *thd_fn(void *args)
{
	int n = *((int *)args);
	printf("this is thread:%d\n", n);
	while(1)
	{
		printf("this is thread:%d\n", n);
		sleep(1);
	}
}

int main(int argc, char *argv[])
{
	pthread_attr_t attr;
	int ret  = pthread_attr_init(&attr);
	if(ret != 0)
	{
		perror("pthread_attr_init_err:");
		printf("pthread_attr_init_err ret:%d\n", ret);
		exit(1);
	}
	size_t default_stack_size = 0;
	ret = pthread_attr_getstacksize(&attr, &default_stack_size);
	if(ret != 0)
	{
		perror("pthread attr getstatck size err:");
		printf("pthread_attr_getstatck_size err. ret:%d\n", ret);
		exit(1);
	}
	printf("the default stack size:%d, %dK\n", default_stack_size, default_stack_size/1024);

	size_t stack_size = 64*1024;
	//size_t stack_size = 128*1024;
	ret = pthread_attr_setstacksize(&attr, stack_size);
	if(ret != 0)
	{
		perror("pthread attr setstatck size");
		printf("pthread_attr_setstatcksize err, size :%d(%dK). ret:%d\n",stack_size, stack_size/1024, ret);
		exit(1);
	}	

	int i = 0;
	for(; i<10; i++)
	{
		pthread_t pid;
		ret = pthread_create(&pid, &attr, thd_fn, (void *)&i);
		if(ret != 0 )
		{
			perror("pthread err:");
			printf("ret:%d\n", ret);
		}
	}
	while(1);

	return 0;
}

###編譯運行

如下所示,默認的線程棧大小爲8192K,但將棧大小設置爲64K 時,運行出錯返回值爲 22.

$ gcc pthread_test.c -g -o pthread_test -pthread
$ ./pthread_test 
the default stack size:8388608, 8192K
pthread attr setstatck size: Success
pthread_attr_setstatcksize err, size :65536(64K). ret:22

根據這種情況,先查看pthread_attr_setstacksize 說明看看能不能找到一些說明信息,其中對返回出錯的一段描述如下的所示。根據其說明是大小設置必須爲頁大小的倍數,還有一個返回碼爲EINVAL 時表示棧大小小於最小要求16K。 通過getconf PAGESIZE 可知當前的頁大小爲16K,而代碼裏面設置的大小爲64K, 符合大小須頁大小的倍數這一要求,並且也超過了16K的最小值。事出怪異,必有妖~

$ man pthread_attr_setstacksize
ERRORS
       pthread_attr_setstacksize() can fail with the following error:

       EINVAL The stack size is less than PTHREAD_STACK_MIN (16384) bytes.

       On some systems, pthread_attr_setstacksize() can fail with the error EINVAL if stacksize is not a multiple of the system page size.
# 查看頁大小
$ getconf PAGESIZE
16384

接下來只能看返回值22 對應的是什麼錯誤了,還有說明中EINVAL 值是多少。 linux 平臺錯誤碼定義在/usr/include/asm/errno.h 文件中。 但grep "EINVAL" asm/errno.h 沒見有結果。 查看cat asm/errno.h 發現裏面包含了文件 asm-generic/errno-base.h 。執行grep "EINVAL" asm-generic/errno-base.h -rn 查找到了相關定義./asm-generic/errno-base.h:26:#define EINVAL 22 /* Invalid argument */
_好消息是這個返回值剛和man 裏面的說明一致,但是man裏面說出這個錯誤是因爲棧大小小於 PTHREAD_STACK_MIN (16384)。莫非man 騙我,不太可能吧。本着懷疑的精神(試試又不會懷孕),推測是這個說明是針對x86平臺的,而我手裏的是MIPS64平臺。 那麼接下來看看宏PTHREAD_STACK_MIN的定義。通過grep 大法找到了PTHREAD_STACK_MIN在此的定義是 131072 即128K。 呵呵呵呵,只要套路深,鐵柱變成針… 改代碼把大小設置爲128K之後運行正常。

# 查找線程棧大小的最小值定義
$ cd /usr/include
$ grep "PTHREAD_STACK_MIN" . -rni
./mips64el-linux-gnuabi64/bits/local_lim.h:81:#define PTHREAD_STACK_MIN	131072
./pthread.h:363:   minimal size of the block must be PTHREAD_STACK_MIN.  */
./pthread.h:374:   to be started.  This size must never be less than PTHREAD_STACK_MIN

總結:
龍芯(MIPS64)平臺,線程棧的大小設置要求: 1. 必須是頁大小(16K)的整數倍 2. 線程棧的最小值在此平臺的定義爲 128K。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章