/*****************************************************************************
Zaczerpnięto z "Linux Programmer's Guide - Rozdział 6"
(C)opyright 1994-1995, Scott Burkett
*****************************************************************************
MODUŁ: semtool.c
*****************************************************************************
Narzędzie zarządzające semaforami stylu SysV z linii poleceń
*****************************************************************************/
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
/* U mnie ( RedHat6.0, jądro 2.2.12-20 )
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h> */
#define SEM_RESOURCE_MAX 1 /* wartość inicjująca wszystkie semafory */
void opensem(int *sid, key_t key);
void createsem(int *sid, key_t key, int members);
void locksem(int sid, int member);
void unlocksem(int sid, int member);
void removesem(int sid);
unsigned short get_member_count(int sid);
int getval(int sid, int member);
void dispval(int sid, int member);
void changemode(int sid, char *mode);
void usage(void);
int main(int argc, char *argv[])
{
key_t key;
int semset_id;
if(argc == 1)
usage();
/* tworzymy unikalny klucz za pomocą wywołania ftok() */
key = ftok(".", 's');
switch(tolower(argv[1][0]))
{
case 's': if(argc != 3)
usage();
createsem(&semset_id, key, atoi(argv[2]));
break;
case 'z': if(argc != 3)
usage();
opensem(&semset_id, key);
locksem(semset_id, atoi(argv[2]));
break;
case 'o': if(argc != 3)
usage();
opensem(&semset_id, key);
unlocksem(semset_id, atoi(argv[2]));
break;
case 'u': opensem(&semset_id, key);
removesem(semset_id);
break;
case 't': opensem(&semset_id, key);
changemode(semset_id, argv[2]);
break;
default: usage();
}
return(0);
}
void opensem(int *sid, key_t key)
{
/* otwórz zestaw semaforów, nie twórz go! */
if((*sid = semget(key, 0, 0666)) == -1)
{
printf("Zestaw semaforów nie istnieje!\n");
exit(1);
}
}
void createsem(int *sid, key_t key, int members)
{
int cntr;
union semun semopts;
if(members > SEMMSL) {
printf("Przykro mi, maxymalną liczbą semaforów w zestawie jest %d\n",
SEMMSL);
exit(1);
}
printf("Próbuję utworzyć nowy zestaw semaforów z %d elementami\n",
members);
if((*sid = semget(key, members, IPC_CREAT|IPC_EXCL|0666))
== -1)
{
fprintf(stderr, "Zestaw semaforów istnieje!\n");
exit(1);
}
semopts.val = SEM_RESOURCE_MAX;
/* Inicjalizacja wszystkich członków ( można to zrobić za pomocą SETALL ) */
for(cntr=0; cntr<members; cntr++)
semctl(*sid, cntr, SETVAL, semopts);
}
void locksem(int sid, int member)
{
struct sembuf sem_lock={ 0, -1, IPC_NOWAIT};
if( member<0 || member>(get_member_count(sid)-1))
{
fprintf(stderr, "%d - członek semaforu poza zasięgiem\n", member);
return;
}
/* Próba zablokowania zestawu semaforów */
if(!getval(sid, member))
{
fprintf(stderr, "Zasoby semaforu wyczerpane ( brak blokady )!\n");
exit(1);
}
sem_lock.sem_num = member;
if((semop(sid, &sem_lock, 1)) == -1)
{
fprintf(stderr, "Blokowanie nie powiodło się\n");
exit(1);
}
else
printf("Zasoby semaforu zmiejszone o jeden ( zablokowane )\n");
dispval(sid, member);
}
void unlocksem(int sid, int member)
{
struct sembuf sem_unlock={ member, 1, IPC_NOWAIT};
int semval;
if( member<0 || member>(get_member_count(sid)-1))
{
fprintf(stderr, "%d - członek semaforu poza zasięgiem\n", member);
return;
}
/* Czy semafor jest zablokowany? */
semval = getval(sid, member);
if(semval == SEM_RESOURCE_MAX) {
fprintf(stderr, "Semafor nie jest zablokowany!\n");
exit(1);
}
sem_unlock.sem_num = member;
/* Próba odblokowania semaforu */
if((semop(sid, &sem_unlock, 1)) == -1)
{
fprintf(stderr, "Odblokowywanie nie powiodło się\n");
exit(1);
}
else
printf("Zasoby semaforu zwiększone o jeden ( odblokowane )\n");
dispval(sid, member);
}
void removesem(int sid)
{
semctl(sid, 0, IPC_RMID, 0);
printf("Usunięto zestaw semaforów\n");
}
unsigned short get_member_count(int sid)
{
union semun semopts;
struct semid_ds mysemds;
semopts.buf = &mysemds;
semctl(sid, 0, IPC_STAT, semopts);
/* zwraca liczbę członków zestawu semaforów */
return(semopts.buf->sem_nsems);
}
int getval(int sid, int member)
{
int semval;
semval = semctl(sid, member, GETVAL, 0);
return(semval);
}
void changemode(int sid, char *mode)
{
int rc;
union semun semopts;
struct semid_ds mysemds;
/* pobierz aktalną wartość wewnętrznej struktury */
semopts.buf = &mysemds;
rc = semctl(sid, 0, IPC_STAT, semopts);
if (rc == -1) {
perror("semctl");
exit(1);
}
printf("Stare prawa dostępu: %o\n", semopts.buf->sem_perm.mode);
/* Zmień prawa dostępu do zestawu semaforów */
sscanf(mode, "%ho", &semopts.buf->sem_perm.mode);
/* Zaktualizuj wewnętrzną strukturę danych */
semctl(sid, 0, IPC_SET, semopts);
printf("Zaktualizowano...\n");
}
void dispval(int sid, int member)
{
int semval;
semval = semctl(sid, member, GETVAL, 0);
printf("semval elementu %d to %d\n", member, semval);
}
void usage(void)
{
fprintf(stderr, "semtool - narzędzie do majstrowania przy semaforach\n");
fprintf(stderr, "\nUŻYCIE: semtool (s)twórz <ilość semaforów>\n");
fprintf(stderr, " (z)ablokuj <nr sem.>\n");
fprintf(stderr, " (o)dblokuj <nr sem.>\n");
fprintf(stderr, " (u)suń\n");
fprintf(stderr, " (t)ryb <tryb>\n");
exit(1);
}