Linux下C语言实现显示SYSTEM V信号量信息的小工具

时间:2021-10-11 19:12:09

1、源代码

/*************************************************************************
  > File Name: svsem_myls.c
  > Author:zhangshengshan
  > Mail: zsszsszsszss@126.com 
  > show all the semophmore
 ************************************************************************/
#include<stdio.h>
#include<sys/types.h>
#include<stdlib.h>
#include<sys/sem.h>
#include "semun.h"
#include <sys/ipc.h>
int get_sem_index(int *pIndex,union semun *pSemun)
{
	*pIndex = semctl(0,0,SEM_INFO,*pSemun);

	if (-1==*pIndex)
	{
		return -1;
	}
	return *pIndex;
}
int main(int argc,char * argv[]){

	union semun union_sem;
	union semun arg;
	union semun dummy;
	struct semid_ds ds_sem;
	struct seminfo info_sem;
	int index=-1;
	int id_sem=0;
	int num_sem=0;
	int i=-1;
	int j=-1;
	int k=-1;

	union_sem.__buf=&info_sem;
	//arg.buf=&ds_sem;
	//从内核获取信号量的索引  
	if( -1==get_sem_index(&index,&union_sem))
	{
		printf("get index failure!\n");
		exit(1);
	}
	//show_semid();
	printf("semid  num  sem# value SEMPID SEMNCNT SEMZCNT\n");
	for (i=0;i<=index;i++)
	{
		arg.buf=&ds_sem;
		//获取信号集描述符
		id_sem=semctl(i,0,SEM_STAT,arg);
		k=arg.buf->sem_nsems;
		//show  every sem info in id_sem
		//member array is a pointor!
		arg.array=calloc(arg.buf->sem_nsems,sizeof(arg.array[0]));
		if (arg.array == NULL)
		{
			printf("calloc error!\n");
			exit (9);
		}
		// here the param will be changed! because it is a union!
		if (semctl(id_sem,0,GETALL,arg)==-1)
		{
			printf("semctl-getALL\n");
			exit(8);
		}
		printf("now arg.buf->sem_nsems is %d, and ds_sem.sem_nsems is %d\n",arg.buf->sem_nsems,ds_sem.sem_nsems);	
		//printf("sem # value  SEMPID SEMNCNT SEMZCNT\n");
		for(j=0;/**/ j<k;j++)
		{
			printf("%5d %5d %3d %5d %5d %5d %5d\n",id_sem,k,j,arg.array[j],\
					semctl(id_sem,j,GETPID,dummy),\
					semctl(id_sem,j,GETNCNT,dummy),\
					semctl(id_sem,j,GETZCNT,dummy));
		}
	}
	return 0;
}

2、程序运行结果

编译上述程序并且运行可以得到结果为:

Linux下C语言实现显示SYSTEM V信号量信息的小工具

这里,semid列表示信号集标识符号、每一个信号集合中可能有多个信号量。这里显示的图形表示163840信号集合现在有两个信号量,而信号集合196609中
包含三个信号量。

3、相关数据结构


3.1 union semun结构

 
在进行信号量相关编程的时候经常需要提供union semun共用体,该公用体需要用户自行实现。这里的semid_ds是描述信号量集合的结构体。

3.2 struct semid_ds结构体

 
该结构体描述了信号量集合的相关信息,其中sem_perm成员描述了该信号量集合的属性和权限,而sem_nsems成员则表示该信号量集合中具有多少成员。

4、semct()函数及相关标志

semctl函数提供了对信号量集合以及信号量的种种操作,上图的DESCRIPTION中清楚的描述了semtcl所需要的各个函数的含义。
我们在程序中使用了
*pIndex = semctl(0,0,SEM_INFO,*pSemun);
SEM_INFO标志同IPC_INFO 标志基本相同,在帮助手册中其描述如下:
可见其主要功能是返回seminfo的结构体,描述相关额信息,seminfo结构体可以在Linux下man semctl 查看。
那么这里的semctl返回的数值是什么含义呢?
可见在 使用了SEM_INFO的情况下,得到的返回值是 the index of the highest used entry in the kernel's internal array recording information about all semaphore sets(得到的是内核中记录所有信号量集合中最大的那个记录),关键是后面的的这句话比较关键,给出了如何获取信号量集合描述符号的方法,this information can be used with repeated SEM_STAT operations to obtain information about all semaphore sets on the system.
 
 
这里请注意在使用SEM_STAT获取相关信号量集合semctl函数的第一个参数semid不是通常意义下的信号量集合的标识符号(即不是通过semget()获取到的标识符号!),而是使用SEM_INFO标志semctl()获得的内核的符号。

5、程序整体思路

1、利用semctl()和SEM_INFO从内核获取系统中的信号量共有多少个?

*pIndex = semctl(0,0,SEM_INFO,*pSemun);

2、循环利用semctl()和SEM_STAT获取信号量集合的描述符号(这个描述符号对应semget()获取的信号集合的描述符号)

id_sem=semctl(i,0,SEM_STAT,arg);

3、循环利用semctl()和GETALL获取每个信号集合中的所有信号量的信息,并且打印相关信息。

if (semctl(id_sem,0,GETALL,arg)==-1)