/* ================================================================================ RPL/2 (R) version 4.1.32 Copyright (C) 1989-2020 Dr. BERTRAND Joël This file is part of RPL/2. RPL/2 is free software; you can redistribute it and/or modify it under the terms of the CeCILL V2 License as published by the french CEA, CNRS and INRIA. RPL/2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL V2 License for more details. You should have received a copy of the CeCILL License along with RPL/2. If not, write to info@cecill.info. ================================================================================ */ #include "rpl-conv.h" // Les fonctions suivantes ne sont utilisées que dans le cas d'un // système POSIX qui ne possède pas de sémaphores anonymes. MacOS X // est dans ce cas. static unsigned char * nom_segment_semaphore(pid_t pid, int ordre) { unsigned char *fichier; if ((fichier = sys_malloc((1 + 256 + 1) * sizeof(unsigned char))) == NULL) { return(NULL); } sprintf(fichier, "/RPL-%llu-%d", (unsigned long long) pid, ordre); return(fichier); } static unsigned char * nom_segment_semaphore_thread(pid_t pid, pthread_t tid, int ordre) { unsigned char *fichier; if ((fichier = sys_malloc((1 + 256 + 1) * sizeof(unsigned char))) == NULL) { return(NULL); } sprintf(fichier, "/RPL-%llu-%llu-%d", (unsigned long long) pid, (unsigned long long) tid, ordre); return(fichier); } /* ================================================================================ Fonctions d'émulation de sémaphores anonymes ================================================================================ Entrées : -------------------------------------------------------------------------------- Sorties : -------------------------------------------------------------------------------- Effets de bord : néant ================================================================================ */ sem_t * sem_init2(unsigned int valeur, pid_t pid, int ordre) { sem_t *semaphore; unsigned char *chemin; unsigned char *langue; if ((chemin = nom_segment_semaphore(pid, ordre)) == NULL) { return(SEM_FAILED); } if ((semaphore = sem_open(chemin, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, valeur)) == SEM_FAILED) { if (errno == EEXIST) { if ((langue = getenv("LANG")) != NULL) { if (strncmp(langue, "fr", 2) == 0) { uprintf("+++Attention : Le sémaphore %s préexiste !\n", chemin); } else { uprintf("+++Warning: %s semaphore preexists!\n", chemin); } } else { uprintf("+++Warning: %s semaphore preexists!\n", chemin); } if (sem_unlink(chemin) != 0) { sys_free(chemin); return(SEM_FAILED); } semaphore = sem_open(chemin, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, valeur); } } sys_free(chemin); return(semaphore); } sem_t * sem_init3(unsigned int valeur, pid_t pid, pthread_t tid, int ordre) { sem_t *semaphore; unsigned char *chemin; unsigned char *langue; if ((chemin = nom_segment_semaphore_thread(pid, tid, ordre)) == NULL) { return(SEM_FAILED); } if ((semaphore = sem_open(chemin, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, valeur)) == SEM_FAILED) { if (errno == EEXIST) { if ((langue = getenv("LANG")) != NULL) { if (strncmp(langue, "fr", 2) == 0) { uprintf("+++Attention : Le sémaphore %s préexiste !\n", chemin); } else { uprintf("+++Warning: %s semaphore preexists!\n", chemin); } } else { uprintf("+++Warning: %s semaphore preexists!\n", chemin); } semaphore = sem_open(chemin, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR, valeur); } } sys_free(chemin); return(semaphore); } sem_t * sem_open2(pid_t pid, int ordre) { unsigned char *chemin; sem_t *semaphore; if ((chemin = nom_segment_semaphore(pid, ordre)) == NULL) { return(SEM_FAILED); } semaphore = sem_open(chemin, O_RDWR); sys_free(chemin); return(semaphore); } int sem_destroy2(sem_t *semaphore, pid_t pid, int ordre) { int erreur; unsigned char *chemin; sem_close(semaphore); if ((chemin = nom_segment_semaphore(pid, ordre)) == NULL) { return(1); } erreur = sem_unlink(chemin); sys_free(chemin); return(erreur); } int sem_destroy3(sem_t *semaphore, pid_t pid, pthread_t tid, int ordre) { int erreur; unsigned char *chemin; sem_close(semaphore); if ((chemin = nom_segment_semaphore_thread(pid, tid, ordre)) == NULL) { return(1); } erreur = sem_unlink(chemin); sys_free(chemin); return(erreur); } int sem_getvalue2(sem_t *semaphore, int *valeur) { int i; int j; logical1 drapeau_fin; struct timespec attente; attente.tv_sec = 0; attente.tv_nsec = GRANULARITE_us * 1000; for(j = 0; j < 100; j++) { if (pthread_mutex_trylock(&mutex_sem) == 0) { (*valeur) = 0; drapeau_fin = d_faux; do { if (sem_trywait(semaphore) == -1) { if (errno == EAGAIN) { // Le sémaphore avait une valeur nulle drapeau_fin = d_vrai; } else { // Autre erreur pthread_mutex_unlock(&mutex_sem); return(-1); } } else { (*valeur)++; } } while(drapeau_fin == d_faux); for(i = 0; i < (*valeur); i++) { if (sem_post(semaphore) != 0) { pthread_mutex_unlock(&mutex_sem); return(-1); } } pthread_mutex_unlock(&mutex_sem); return(0); } nanosleep(&attente, NULL); INCR_GRANULARITE(attente.tv_nsec); } // Le mutex n'a pas pu être verrouillé. On peut raisonnablement penser // que le sémaphore est bloqué dans un sem_wait() protégé par ce mutex. (*valeur) = 0; return(0); } #undef sem_post #undef sem_wait #undef sem_trywait #ifdef IPCS_SYSV /* ================================================================================ Fonctions d'émulation de sémaphores POSIX en fonction des sémaphores SysV ================================================================================ Entrées : -------------------------------------------------------------------------------- Sorties : -------------------------------------------------------------------------------- Effets de bord : néant ================================================================================ */ #ifndef OS2 // IPCS_SYSV extern unsigned char *racine_segment; #else // OS/2 unsigned char racine_semaphores_OS2[] = "\\SEM32\\"; unsigned char racine_memoire_OS2[] = "\\SHAREMEM\\"; #endif int sem_init_SysV(sem_t *semaphore, int shared, unsigned int valeur) { // Création d'un sémaphore anonyme qui devra être supprimé par // sem_destroy_SysV # ifndef OS2 // IPCS_SYSV int desc; int ios; key_t clef; union semun argument; unsigned char *langue; if (shared == 0) { // Sémaphore privé (*semaphore).sem = semget(IPC_PRIVATE, 1, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR); (*semaphore).path = NULL; (*semaphore).pid = getpid(); (*semaphore).tid = pthread_self(); (*semaphore).alloue = 0; } else { // Sémaphore partagé entre plusieurs processus if (((*semaphore).path = sys_malloc((strlen(racine_segment) + 2 + 256 + 1) * sizeof(unsigned char))) == NULL) { return(-1); } sprintf((*semaphore).path, "%s/RPL-SEMAPHORE-%d-%llX-%llX", racine_segment, (int) getpid(), (long long unsigned) pthread_self(), (long long unsigned) semaphore); if ((desc = open((*semaphore).path, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) == -1) { if (errno != EEXIST) { sys_free((*semaphore).path); return(-1); } if ((langue = getenv("LANG")) != NULL) { if (strncmp(langue, "fr", 2) == 0) { uprintf("+++Attention : Le sémaphore %s préexiste !\n", (*semaphore).path); } else { uprintf("+++Warning: %s semaphore preexists!\n", (*semaphore).path); } } else { uprintf("+++Warning: %s semaphore preexists!\n", (*semaphore).path); } if ((desc = open((*semaphore).path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) == -1) { sys_free((*semaphore).path); return(-1); } } (*semaphore).pid = getpid(); (*semaphore).tid = pthread_self(); clef = ftok((*semaphore).path, 1); close(desc); if (clef == -1) { sys_free((*semaphore).path); return(-1); } (*semaphore).alloue = 0; (*semaphore).sem = semget(clef, 1, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR); } if ((*semaphore).sem == -1) { errno = EINVAL; return(-1); } argument.val = (int) valeur; ios = semctl((*semaphore).sem, 0, SETVAL, argument); return(ios); # else // OS/2 sem_t *psem; psem = semaphore; if (((*psem).cnt = sys_malloc(sizeof(ULONG))) == NULL) { sys_free(psem); errno = ENOMEM; return(-1); } if (((*psem).nopened = sys_malloc(sizeof(ULONG))) == NULL) { sys_free((*psem).cnt); sys_free(psem); errno = ENOMEM; return(-1); } if (DosCreateMutexSem(NULL, &((*psem).hmtx), 0, 0) != 0) { sys_free((*psem).cnt); sys_free((*psem).nopened); sys_free(psem); return(-1); } if (DosCreateEventSem(NULL, &((*psem).hev), 0, (valeur != 0) ? 1 : 0) != 0) { DosCloseMutexSem((*psem).hmtx); sys_free((*psem).cnt); sys_free((*psem).nopened); sys_free(psem); return(-1); } (*(*psem).cnt) = valeur; (*(*psem).nopened) = 1; (*psem).shared = shared; (*psem).allocated = 0; return(0); # endif } int sem_destroy_SysV(sem_t *semaphore) { // Détruit un sémaphore anonmyme # ifndef OS2 // IPCS_SYSV if ((*semaphore).path != NULL) { return(EINVAL); } if ((*semaphore).pid != getpid()) { return(0); } if (semctl((*semaphore).sem, 0, IPC_RMID) == -1) { return(EINVAL); } return(0); # else // OS/2 sem_t *psem; psem = semaphore; if (DosRequestMutexSem((*psem).hmtx, SEM_INDEFINITE_WAIT) != 0) { return(EINVAL); } if (DosCloseMutexSem((*psem).hmtx) != 0) { return(EINVAL); } while(DosCloseEventSem((*psem).hev) == ERROR_SEM_BUSY) { DosPostEventSem((*psem).hev); } (*(*psem).nopened)--; if ((*psem).shared == 0) { sys_free((*psem).cnt); sys_free((*psem).nopened); } else { if ((*(*psem).nopened) == 0) { DosFreeMem((*psem).cnt); } } if ((*psem).allocated != 0) { sys_free(psem); } return(0); # endif } int sem_wait_SysV(sem_t *semaphore) { # ifndef OS2 // IPCS_SYSV struct sembuf commande; // semop() ne renvoie pas EINTR sur un signal ! commande.sem_num = 0; commande.sem_op = -1; commande.sem_flg = 0; if (semop((*semaphore).sem, &commande, 1) == -1) { if (errno != EAGAIN) { errno = EINVAL; return(-1); } else { return(-1); } } return(0); # else // OS/2 sem_t *psem; ULONG cnt; psem = semaphore; if (DosWaitEventSem((*psem).hev, SEM_INDEFINITE_WAIT) != 0) { errno = EINVAL; return(-1); } if (DosRequestMutexSem((*psem).hmtx, SEM_INDEFINITE_WAIT) != 0) { errno = EINVAL; return(-1); } if ((*(*psem).cnt) > 0) { (*(*psem).cnt)--; } if ((*(*psem).cnt) == 0) { DosResetEventSem((*psem).hev, &cnt); } DosReleaseMutexSem((*psem).hmtx); return(0); # endif } int sem_trywait_SysV(sem_t *semaphore) { # ifndef OS2 // IPCS_SYSV struct sembuf commande; commande.sem_num = 0; commande.sem_op = -1; commande.sem_flg = IPC_NOWAIT; if (semop((*semaphore).sem, &commande, 1) == -1) { return(-1); } return(0); # else // OS/2 int ios; sem_t *psem; ULONG cnt; psem = semaphore; if ((ios = DosWaitEventSem((*psem).hev, SEM_IMMEDIATE_RETURN)) != 0) { errno = (ios == ERROR_TIMEOUT) ? EAGAIN : EINVAL; return(-1); } if (DosRequestMutexSem((*psem).hmtx, SEM_INDEFINITE_WAIT) != 0) { errno = EINVAL; return(-1); } if ((*(*psem).cnt) > 0) { (*(*psem).cnt)--; } if ((*(*psem).cnt) == 0) { DosResetEventSem((*psem).hev, &cnt); } DosReleaseMutexSem((*psem).hmtx); return(0); # endif } #ifndef timespeccmp # define timespeccmp(tsp, usp, cmp) \ (((tsp)->tv_sec == (usp)->tv_sec) ? \ ((tsp)->tv_nsec cmp (usp)->tv_nsec) : \ ((tsp)->tv_sec cmp (usp)->tv_sec)) # define timespecadd(tsp, usp, vsp) \ do { \ (vsp)->tv_sec = (tsp)->tv_sec + (usp)->tv_sec; \ (vsp)->tv_nsec = (tsp)->tv_nsec + (usp)->tv_nsec; \ if ((vsp)->tv_nsec >= 1000000000L) { \ (vsp)->tv_sec++; \ (vsp)->tv_nsec -= 1000000000L; \ } \ } while(0) # define timespecsub(tsp, usp, vsp) \ do { \ (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \ (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \ if ((vsp)->tv_nsec < 0) { \ (vsp)->tv_sec--; \ (vsp)->tv_nsec += 1000000000L; \ } \ } while(0) #endif int sem_timedwait_SysV(sem_t *sem, struct timespec *ts) { struct timespec onems = { 0, 1000000 }; struct timespec total = { 0, 0 }; struct timespec unslept; struct timespec elapsed; struct timespec tmp; while(timespeccmp(ts, &total, >)) { if (sem_trywait_SysV(sem) == 0) { return(0); } if (errno != EAGAIN) { return(-1); } nanosleep(&onems, &unslept); timespecsub(&onems, &unslept, &elapsed); timespecadd(&total, &elapsed, &tmp); total.tv_sec = tmp.tv_sec; total.tv_nsec = tmp.tv_nsec; } errno = ETIMEDOUT; return(-1); } int sem_post_SysV(sem_t *semaphore) { # ifndef OS2 // IPCS_SYSV struct sembuf commande; commande.sem_num = 0; commande.sem_op = 1; commande.sem_flg = 0; while(semop((*semaphore).sem, &commande, 1) == -1) { if (errno != EINTR) { errno = EINVAL; return(-1); } } return(0); # else // OS/2 sem_t *psem; psem = semaphore; if (DosRequestMutexSem((*psem).hmtx, SEM_INDEFINITE_WAIT) != 0) { errno = EINVAL; return(-1); } (*(*psem).cnt)++; DosPostEventSem((*psem).hev); DosReleaseMutexSem((*psem).hmtx); return(0); # endif } int sem_getvalue_SysV(sem_t *semaphore, int *valeur) { # ifndef OS2 // IPCS_SYSV (*valeur) = semctl((*semaphore).sem, 0, GETVAL); if ((*valeur) < 0) { return(EINVAL); } return(0); # else sem_t *psem; psem = semaphore; if (DosRequestMutexSem((*psem).hmtx, SEM_INDEFINITE_WAIT) != 0) { errno = EINVAL; return(-1); } (*valeur) = (*(*psem).cnt); DosReleaseMutexSem((*psem).hmtx); return(0); # endif } sem_t *sem_open_SysV(const char *nom, int oflag, ...) //*sem_open(const char *nom, int oflag) //*sem_open(const char *nom, int oflag, mode_t mode, unsigned int value) { mode_t mode; sem_t *semaphore; # ifndef OS2 int desc; key_t clef; union semun argument; unsigned char *langue; # endif unsigned char *nom_absolu; unsigned int valeur; va_list liste; # ifdef OS2 sem_t *psem; PVOID base; unsigned char *ptr; unsigned char *nom_segment; # endif # ifndef OS2 // IPCS_SYSV if ((nom_absolu = sys_malloc((strlen(racine_segment) + strlen(nom) + 2) * sizeof(unsigned char))) == NULL) { return(SEM_FAILED); } sprintf(nom_absolu, "%s/%s", racine_segment, nom); if ((semaphore = sys_malloc(sizeof(sem_t))) == NULL) { return(SEM_FAILED); } (*semaphore).alloue = -1; (*semaphore).pid = getpid(); (*semaphore).tid = pthread_self(); # else if ((nom_segment = sys_malloc((strlen(racine_memoire_OS2) + strlen(nom) + 1) * sizeof(unsigned char))) == NULL) { return(SEM_FAILED); } sprintf(nom_segment, "%s%s", racine_memoire_OS2, nom); ptr = nom_segment; while((*ptr) != d_code_fin_chaine) { if ((*ptr) == '/') { (*ptr) = '\\'; } ptr++; } if ((nom_absolu = sys_malloc((strlen(racine_semaphores_OS2) + strlen(nom) + 2) * sizeof(unsigned char))) == NULL) { return(SEM_FAILED); } sprintf(nom_absolu, "%s%s", racine_semaphores_OS2, nom); ptr = nom_absolu; while((*ptr) != d_code_fin_chaine) { if ((*ptr) == '/') { (*ptr) = '\\'; } ptr++; } (*(ptr + 1)) = d_code_fin_chaine; if ((psem = sys_malloc(sizeof(sem_t))) == NULL) { return(SEM_FAILED); } (*psem).allocated = 1; # endif if ((oflag & O_CREAT) == 0) { // 2 arguments # ifndef OS2 // IPCS_SYSV clef = ftok(nom_absolu, 1); if (clef == -1) { return(SEM_FAILED); } (*semaphore).sem = semget(clef, 0, 0); (*semaphore).path = nom_absolu; (*semaphore).pid = getpid(); if ((*semaphore).sem == -1) { sys_free(semaphore); sys_free(nom_absolu); return(SEM_FAILED); } # else // OS/2 if ((psem = sys_malloc(sizeof(sem_t))) == NULL) { sys_free(nom_absolu); sys_free(nom_segment); return(SEM_FAILED); } (*ptr) = 'M'; if (DosOpenMutexSem(nom_absolu, &((*psem).hmtx)) != 0) { sys_free(psem); sys_free(nom_absolu); sys_free(nom_segment); return(SEM_FAILED); } (*ptr) = 'S'; if (DosOpenEventSem(nom_absolu, &((*psem).hev)) != 0) { DosCloseMutexSem((*psem).hmtx); sys_free(psem); sys_free(nom_absolu); sys_free(nom_segment); return(SEM_FAILED); } if (DosGetNamedSharedMem(&base, nom_segment, PAG_WRITE | PAG_READ) != 0) { DosCloseMutexSem((*psem).hmtx); sys_free(nom_absolu); sys_free(nom_segment); sys_free(psem); return(SEM_FAILED); } sys_free(nom_segment); (*psem).cnt = (ULONG *) base; (*psem).nopened = ((ULONG *) base) + 1; (*psem).shared = 1; if (DosRequestMutexSem((*psem).hmtx, SEM_INDEFINITE_WAIT) != 0) { DosCloseMutexSem((*psem).hmtx); sys_free(nom_absolu); sys_free(nom_segment); sys_free(psem); return(SEM_FAILED); } (*((*psem).nopened))++; DosReleaseMutexSem((*psem).hmtx); semaphore = psem; # endif } else { // 4 arguments // O_CREAT O_EXCL // S_IRUSR S_IWUSR va_start(liste, oflag); mode = va_arg(liste, mode_t); valeur = va_arg(liste, unsigned int); va_end(liste); # ifndef OS2 // IPCS_SYSV if ((desc = open(nom_absolu, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR)) == -1) { if (errno != EEXIST) { sys_free(semaphore); sys_free(nom_absolu); return(SEM_FAILED); } if ((langue = getenv("LANG")) != NULL) { if (strncmp(langue, "fr", 2) == 0) { uprintf("+++Attention : Le sémaphore %s préexiste !\n", nom_absolu); } else { uprintf("+++Warning: %s semaphore preexists!\n", nom_absolu); } } else { uprintf("+++Warning: %s semaphore preexists!\n", nom_absolu); } if ((desc = open(nom_absolu, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) == -1) { sys_free(semaphore); sys_free(nom_absolu); return(SEM_FAILED); } } if ((clef = ftok(nom_absolu, 1)) == -1) { close(desc); sys_free(semaphore); sys_free(nom_absolu); return(SEM_FAILED); } close(desc); (*semaphore).sem = semget(clef, 1, (((oflag & O_CREAT) == 0) ? 0 : IPC_CREAT) | (((oflag & O_EXCL) == 0) ? 0 : IPC_EXCL) | (int) mode); (*semaphore).path = nom_absolu; (*semaphore).pid = getpid(); if ((*semaphore).sem == -1) { sys_free(semaphore); sys_free(nom_absolu); return(SEM_FAILED); } argument.val = (int) valeur; semctl((*semaphore).sem, 0, SETVAL, argument); # else // OS/2 if ((psem = sys_malloc(sizeof(sem_t))) == NULL) { sys_free(nom_absolu); sys_free(nom_segment); return(SEM_FAILED); } (*ptr) = 'M'; if (DosCreateMutexSem(nom_absolu, &((*psem).hmtx), 0, 0) != 0) { sys_free(psem); sys_free(nom_absolu); sys_free(nom_segment); return(SEM_FAILED); } (*ptr) = 'S'; if (DosCreateEventSem(nom_absolu, &((*psem).hev), 0, (valeur != 0) ? 1 : 0) != 0) { DosCloseMutexSem((*psem).hmtx); sys_free(nom_absolu); sys_free(nom_segment); sys_free(psem); return(SEM_FAILED); } if (DosAllocSharedMem(&base, nom_segment, 2 * sizeof(ULONG), PAG_WRITE | PAG_READ | PAG_COMMIT) != 0) { DosCloseMutexSem((*psem).hmtx); sys_free(nom_absolu); sys_free(nom_segment); sys_free(psem); return(SEM_FAILED); } sys_free(nom_segment); (*psem).cnt = (ULONG *) base; (*psem).nopened = ((ULONG *) base) + 1; (*(*psem).cnt) = valeur; (*(*psem).nopened) = 1; (*psem).shared = 1; semaphore = psem; # endif } return(semaphore); } int sem_close_SysV(sem_t *semaphore) { // Ferme un sémaphore nommé créé par sem_open_SysV() # ifndef OS2 // IPCS_SYSV if ((*semaphore).path != NULL) { sys_free((*semaphore).path); } if ((*semaphore).alloue == -1) { sys_free(semaphore); } return(0); # else sem_t *psem; psem = semaphore; if (DosCloseMutexSem((*psem).hmtx) != 0) { return(EINVAL); } while(DosCloseEventSem((*psem).hev) == ERROR_SEM_BUSY) { DosPostEventSem((*psem).hev); } (*(*psem).nopened)--; if ((*psem).shared == 0) { sys_free((*psem).cnt); sys_free((*psem).nopened); } else { if ((*(*psem).nopened) == 0) { DosFreeMem((*psem).cnt); } } if ((*psem).allocated != 0) { sys_free(psem); } return(0); # endif } int sem_unlink_SysV(char *nom) { // Détruit un sémaphore nommé créé par sem_open_SysV() # ifndef OS2 // IPCS_SYSV semctl(semget(ftok(nom, 1), 0, 0), 0, IPC_RMID); if (unlink(nom) == -1) { return(EACCES); } sys_free(nom); return(0); # else return(0); # endif } #endif // vim: ts=4