SYSTEM CALL: semctl(); PROTOTYPE: int semctl ( int semid, int semnum, int cmd, union semun arg ); RETURNS: positive integer on success -1 on error: errno = EACCESS (permission denied) EFAULT (invalid address pointed to by arg argument) EIDRM (semaphore set was removed) EINVAL (set doesn't exist, or semid is invalid) EPERM (EUID has no privileges for cmd in arg) ERANGE (semaphore value out of range) NOTES: Performs control operations on a semaphore set
명령어를 지정하기위해 cmd 아규먼트를 사용하는 두 시스템 호출은 IPC 객체에서 수행된다. 남겨진 차이점은 두 호출의 마지막 아규먼트이다. msgctl에서 마지막 아규먼트는 커널에서 사용되는 내부 자료 구조의 복사본을 나타낸다. 큐의 소유권과 허가사항을 바꾸거나 지정하는 것은 물론이고 메세지 큐에 대한 정보를 조회하기위해 이 구조체를 사용했음을 상기하라. 세마퍼에서는 부가적인 동작 명령어를 지원하기위해 마지막 아규먼트로 보다 복잡한 자료 타입이 요구된다. union의 사용은 중요한 단계에서 많은 초보 세마퍼 프로그래머들을 당황하게 만든다. 이러한 혼동을 막기위해 이 구조체를 주의깊게 해부할 것 이다.
semctl()의 첫번째 아규먼트는 semget 호출에 의해 반환된 키값이다. 두번째 아규먼트(semnu)는 동작의 목표가 되는 세마퍼 번호이다. 중요한 것은, 이것이 '0'값으로 표현되는 집합내의 첫번째 세마퍼(또는 오직 한개만 있는 경우)를 가지고 세마퍼 집합의 인덱스로 간주된다는 것이다.
cmd 아규먼트는 집합에 대해서 수행되어지는 명령어를 나타낸다. 잘 알려진 IPC_STAT/IPC_SET 명령어는 세마퍼 집합에서 지정되는 부가적인 명령어의 풍부함과 함께 표현된다.:
/* semctl 시스템 호출에 대한 아규먼트 */ union semun { int val; /* SETVAL을 위한 값 */ struct semid_ds *buf; /* IPC_STAT & IPC_SET을 위한 버퍼 */ ushort *array; /* GETALL & SETALL를 위한 배열 */ struct seminfo *__buf; /* IPC_INFO를 위한 버퍼 */ void *__pad; };
이런 특별한 시스템 호출을 모든 시스템 V IPC 호출을 이해하는데 가장 어려운 점으로 꼽을 수 있으므로,실제로 이러한 다양한 예를 검사할 것이다.
다음의 짧은 코드는 넘겨진 세마퍼의 값을 반환한다. 마지막 아규먼트(union)은 GETVAL 명령어가 사용될 때 무시된다.:
int get_sem_val( int sid, int semnum ) { return( semctl(sid, semnum, GETVAL, 0)); }
#define MAX_PRINTERS 5 printer_usage() { int x; for(x=0; x<MAX_PRINTERS; x++) printf("Printer %d: %d\n\r", x, get_sem_val( sid, x )); }
void init_semaphore( int sid, int semnum, int initval) { union semun semopts; semopts.val = initval; semctl( sid, semnum, SETVAL, semopts); }
msgtool 프로젝트로 부터 IPC_STAT와 IPC_SET 명령어가 큐상의 허가사항을 변경하는데 사용된다는 것을 기억하라. 이런 명령어들이 세마퍼 구현상에서 지원되는 반면에 그것들의 사용은 내부 자료 구조가 단일 개체보다는 연합체(union)의 멤버로 부터 복사되고 조회되는 것과는 다소 다르다. 이 코드안에서 버그를 찾을 수 있겠는가?
/* 요구되는 허가사항은 텍스트로 넘겨져야 한다. (ex: "660") */ void changemode(int sid, char *mode) { int rc; struct semid_ds mysemds; /* 내부 자료 구조의 현재 값을 얻는다 */ if((rc = semctl(sid, 0, IPC_STAT, semopts)) == -1) { perror("semctl"); exit(1); } printf("Old permissions were %o\n", semopts.buf->sem_perm.mode); /* 세마퍼의 허가사항을 바꾼다 */ sscanf(mode, "%o", &semopts.buf->sem_perm.mode); /* 내부 자료 구조를 업데이트한다 */ semctl(sid, 0, IPC_SET, semopts); printf("Updated...\n"); }
IPC_SET/IPC_STAT 명령어가 연합체(union)의 buf 멤버를 사용하고 이것은 semid_ds 타입의 포인터(pointer)임을 기억하라. 포인터의 포인터의 포인터의 포인터! buf 멤버는 우리의 함수가 적당히 일하기 위한 유효한 저장위치를 가리키고 있어야만 한다. 보완된 버전을 살펴보자:
void changemode(int sid, char *mode) { int rc; struct semid_ds mysemds; /* 내부 자료 구조의 현재 값을 얻는다 */ /* 먼저 우리의 국소적인 복사본을 가리킨다! */ semopts.buf = &mysemds; /* 다시 한번 시도해 보자! */ if((rc = semctl(sid, 0, IPC_STAT, semopts)) == -1) { perror("semctl"); exit(1); } printf("Old permissions were %o\n", semopts.buf->sem_perm.mode); /* 세마퍼의 허가사항을 바꾼다 */ sscanf(mode, "%o", &semopts.buf->sem_perm.mode); /* 내부 자료 구조를 업데이트한다 */ semctl(sid, 0, IPC_SET, semopts); printf("Updated...\n"); }
Copyright (c) 1996,1997 by Euibeom.Hwang & SangEun.Oh All Rights Reserved
Email To:Webmaster ,
Another address
LAST UPDATE Nov 25,1997
Created Nov 25,1997