시스템 프로그래밍 - 랩핑함수의 제작
- 라이브러리용 랩핑 함수 sysv_semget은 토큰이나 키값, 세마포어 개수, 초기화할 semval 초기값, 접근모드 입력시 세마포어의 IPC 값 반환함
- 만약 세마포어가 생성되지 않으면 생성하고 초기화
- IPC ID가 이미 존재시 errno == EEXIST를 내고 기존의 세마포어 IPC ID를 알려줌(ID를 초기화하지는 않는다.)
세마포어 생성 라이브러리 함수
int sysv_semget(char *tok, key_t sem_fixkey, int n_sem, int sem_value, int user_mode)
{
int sem_id, i;
union semun semun;
unsigned short int *arr_semval = NULL;
key_t sem_key;
/* if tok is not NULL, we make IPC key for semaphore */
if (tok != NULL) {
if ((sem_key = ftok(tok, 1234)) == -1) {
return -1;
}
} else {
sem_key = sem_fixkey;
}
if ((sem_id = semget(sem_key, n_sem, IPC_CREAT|IPC_EXCL|user_mode)) == -1) {
if (errno == EEXIST) {
sem_id = semget(sem_key, 0, 0);
return sem_id;
}
}
if (sem_id == -1) {
fprintf(stderr,"FAIL: semget [%s:%d]\n", __FUNCTION__, __LINE__);
return -1;
}
/* init semaphore value */
if ((arr_semval = (unsigned short int *) malloc(sizeof(unsigned short int) * n_sem)) == NULL) {
fprintf(stderr, "FAIL: malloc [%s:%d]\n", __FUNCTION__, __LINE__);
return -1;
}
for(i=0; i<n_sem; i++) arr_semval[i] = sem_value;
semun.array = arr_semval;
if (semctl(sem_id, 0, SETALL, semun) == -1) {
fprintf(stderr, "FAIL: semctl [%s:%d]\n", __FUNCTION__, __LINE__);
free(arr_semval); arr_semval = NULL;
return -1;
}
free(arr_semval);
return sem_id;
}
간략적인 해석
1. int sysv_semget(char *tok, key_t sem_fixkey, int n_sem, int sem_value, int user_mode) -> semget함수 호출시 사용자로부터 키값, 세마포어 개수, semval 초기값, 접근모드를 입력받음
2. if (tok != NULL) { -> tok != null이면 ftok 함수를 통해 IPC키을 생성한다. ftok함수시 return 값이면 -1이면 실패
3. else { -> tok == null이면 직접 IPC 키를 입력받는 경우이므로 sem_fixkey를 IPC키로 사용
4. if ((sem_id = semget(sem_key, n_sem, IPC_CREAT|IPC_EXCL|user_mode)) == -1) { -> errno ==EEXIST -> 이미 IPC 아이디 존재하면 IPC_EXCL에 의해 EEXIST에러를 보냄
5. sem_id = semget(sem_key, 0, 0); -> IPC_ID가 존재하는 경우 IPC_ID를 알아내기 위해 semget(id,0,0)을 호출
6. if ((arr_semval = (unsigned short int *) malloc(sizeof(unsigned short int) * n_sem)) == NULL) { -> 세마포어를 할당받았을 경우 힙 메모리를 동적할당 받고 전체 배열을 setall로 초기화함 그 후 사용자가 초기 세마포어 값(sem_value) 초기화
7. semun.array = arr_semval; if (semctl(sem_id, 0, SETALL, semun) == -1) -> 앞에서 할당한 힙 영역의 주소를 semun,array에 전달 -> semctl에 넘겨줌 |
세마포어 세트 삭제 랩핑함수(sysv_senrm)와 특정위치 세마포어 값 읽어오는 함수(sysv_semval)
int sysv_semrm(int sem_id) // 세마포어 삭제
{
if (semctl(sem_id, 0, IPC_RMID) == -1) { // 세마포어 세트를 삭제하는 것이 실패하면
fprintf(stderr, "FAIL: semctl() 'IPC_RMID' [%s:%d]\n", __FUNCTION__, __LINE__); // 에러를 띄운다.
return -1;
}
return 0; // 정상 = 0 비정상 = -1
}
int sysv_semval(int sem_id, int sem_idx) // 특정 위치의 세마포어 값 읽어오기
{
int semval;
if ((semval = semctl(sem_id, sem_idx, GETVAL)) == -1) { // sem_idx : 읽어올 코드 위치, 읽어오는 것 실패하면)
fprintf(stderr, "FAIL: semctl() 'GETVAL' [%s:%d]\n", __FUNCTION__, __LINE__); //에러코드 띄운다.
return -1;
}
return semval; // 에러 = -1 정상 = 특정위치 세마포어 값
}