一万个计划,不如一个行动,从今天开始重新写博客,立志每周至少写一篇,并且要不断坚持下去。
今天比较闲,因为明天要负责别的项目,所以切换期整好可以偷下懒。同事下午给我了一个题目让我帮忙做下,后来才知道他在帮一个国外的妹纸,细节就不多讲了:-)……题目如下,我是用中文回答的:
Youare to develop and answer the following questions:
-
Aprogram which will create a shared memory region.
-
Ifthat region exists, remove the region and try again.
-
Thepointer type to the region is up to your discretion.
-
TheSHMID is based on a key from a local text file in your workingdirectory.
-
Choosethe size of the region to be more than 1 (one) memory page and nota page size multiple (ex size=125445).
-
-
Yourprogram will print out the key id from the SHM region in HEX format.
-
Yourprogram will also capture a signal SIGSEGV.
-
UponSIGSEGV, your program will print out the number of bytes written tothe region.
-
-
Yourprogram will write to the shared memory region until a SIGSEGVoccurs.
-
Writingany random number or a constant of your data type from offset 0until SIGSEGV
-
Thenreset the counter do 4.a again.
-
-
Yourprogram will loop 5 times (step 4 five times).
Questions:
-
Dida SIGSEGV signal occur and what was the number of bytes written tothe region before the signal was captured?
如果只写一次,且你的数据类型的大小不超过共享内存大小,不会发生sigsegv
如果连续写共享内存,假设你设置的共享内存有125445个字节,每页有4096个字节,则共享内存会有31页,即126976个字节,假设每次写4个字节,则会写入126976个字节,然后再继续写就有可能会产生sigsegv
-
Whydid the SIGSEGV occur or what analysis do you have on why it did notoccur.
内存越界
-
Isthere a difference between the number of bytes written than yourrequested size during creation of the SHM region.
thenumber of bytes written:所写内存大小
yourrequested size duringcreation:共享内存最大大小为页整数倍,即4096的整数倍,如果shmget的第二个参数不为4096的整数倍,操作系统会给该共享内存进行4096的对齐
所写的内存大小需要在所创建内存大小范围之内,否则会出现内存越界,会抛出段错误
-
Couldyou complete item 5 of the program? Please explain why or why not.
这个程序不能循环执行,因为程序产生了段错误之后,便会进入信号处理函数处理,处理完之后继续回到出错的地方,该错误会继续产生,即会不断抛出SIGSEGV信号,而无法完成剩下的4次循环
---------------------------------------------------------------------------------------
回过头来看这个题目,貌似这个题目考察以下几个内容
1.shmget函数中第二个参数不论你怎么设置,操作系统会帮你进行页对齐
2.内存越界会产生段错误(关于题干的第四点依然不是很懂,不明白是不断顺序写还是只写一个随机数或常量)
3.SIGSEGV信号的捕获之后,程序的行为如何
今天做这个题目花了不少时间,主要是对共享内存的使用不熟,做题的同时顺便也补补课。在解决第三个问题的时候,发现网上有人用siglongjmp的方式从信号处理函数跳回产生SIGSEGV的地方,然后通过之前保存的sigsetjmp恢复出错之前的环境,想用这样的方式循环五次,但最后还是失败告终,具体为什么会这样还没有弄清楚,代码先保存起来,在这里做个记录,以后有时间再找出具体的原因把。关于这道题的程序代码如下:
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <setjmp.h>
const char *path = "/tmp";
int memsize = 4097;
int count = 0;
unsigned int *tmpbuf = 0;
unsigned int *buf = 0;
sigjmp_buf env;
void recvSignal(int sig)
{
printf("received segment fault, count = %d !!!\n", count);
count = 0;
siglongjmp(env, 1);
}
int main()
{
//signal(SIGSEGV, recvSignal);
key_t key = ftok(path, 'a');
if (key < 0)
{
fprintf(stderr, "ftok err: %s\n", strerror(errno));
return -1;
}
int shmid = shmget(key, memsize, 0666 | IPC_CREAT | IPC_EXCL);
if (shmid < 0)
{
// delete the old
shmid = shmget(key, memsize, 0666 | IPC_CREAT);
shmctl(shmid, IPC_RMID, NULL);
}
// recreate
shmid = shmget(key, memsize, 0666 | IPC_CREAT | IPC_EXCL);
if (shmid < 0)
{
printf("shmget error: %s\n", strerror(errno));
return -1;
}
printf("SHMID=%d\n", shmid);
buf = (unsigned int*)shmat(shmid, NULL, 0);
int i = 0;
for (; i < 5; i++)
{
int r = sigsetjmp(env, 1);
if (r == 0)
{
signal(SIGSEGV, recvSignal);
tmpbuf = buf;
printf("tmpbuf=%x, count=%d\n", tmpbuf, count);
while (1)
{
*(tmpbuf++) = 1;
count += 4;
}
}
else
{
printf("jump back");
}
sleep(5);
}
return 0;
}