socle_bash/lib/semaphore.lib
2017-07-21 09:44:49 +02:00

153 lines
7.1 KiB
Plaintext
Executable File

##----------------------------------------------------------------------------
## Script : semaphore.lib
## Module Puppet : gnc-script_core_dtsi
## Auteur : Emmanuel Confrere
## Date : 16-06-2016
## Version : 3.1.0
## Objet : Gestion de l execution parallel d un shell.
##
## Fonction : fct_unique_exec [nom] [occurences] [mode]
## fct_libere_exec [nom]
##
## [nom] : Mot alphabetique quelconque identifiant la ressource.
## [nom] ne peut pas prendre pour valeur "wait" ou "nowait".
##
## [occurence] : Nombre d execution parallel (Par defaut 1).
##
## [mode] : "wait" (par defaut) ou "nowait".
##
## Rem : Tous les parametres sont facultatif, mais doivent etre presentes dans l'ordre.
##
## Detail : Cette librairie gere les acces concurrent a une portion de code Bash.
## Deux fonctions sont utilisees :
## - fct_unique_exec : Positionne des semaphores et controle la disponibilite.
## - fct_libere_exec : Supprime des semaphores
##
## La fonction fct_unique_exec(), si appelee sans l argument [nom] et/ou [occurences],
## doit etre positionee en debut de script juste apres le chargement du fichier
## ${NC_EXPL_CONF}/init.conf sinon elle peut etre placee a n importe quel endroit dans le code.
##
## Elle positionne une semaphore pour proteger d une execution concurrente.
## Ensuite elle controle la disponibilite de la ressource et selon le [mode] utilise
## "wait ou "nowait", attend sa liberation ou sort immediatement en erreur.
##
## La semaphore est liberee automatiquement par l appel a la fonction fct_erreur(), sauf si [nom] a ete
## utilisee - fct_erreur() appelle la fonction fct_libere_exec() -.
##
## L utilisation avec [nom] implique OBLIGATOIREMENT de liberer la semaphore en appelant
## explicitement fct_libere_exec [nom] dans le script ayant appele fct_unique_exec().
##
## [occurences] fixe le nb d execution concurrente qui peuvent etre executer en parallel
## cette valeur est fixe par defaut avec ${SH_CPT_SEMAPHORE} qui vaut 1 si non
## surcharger par le script.
##
## [mode] fixe le comportement de sortie de la fonction fct_unique_exec().
## Par defaut le mode est fixe a "wait" mais il est possible de demander de ne pas
## attendre et de renvoyer le code erreur 1 en possitionnant la valeur du mode a "nowait".
##
## Les variables SH_FICSEM, SH_PROG et SH_CPT_SEMAPHORE sont initialisees dans le
## fichier ${NC_EXPL_CONF}/init.conf (comme toute les variables SH_*).
## SH_CPT_SEMAPHORE vaut 1 par defaut et peut etre surcharge dans le fichier
## de configuration du script.
# ----------------------------------------------------------------------------
# Mise a jour :
# 1.0.0 - Emmanuel Confrere - Creation
# 1.0.1 - Daniel Frochtmann - Parallelisation de traitement
# 1.0.2 - Emmanuel Confrere - Ajout de commentaire
# 2.0.0 - Emmanuel Confrere - Debug (Ne fonctionnais pas si plus de 2 occurance)
# Refonte complete. On se base maintenant sur une liste de PID
# 2.1.0 - Emmanuel Confrere - Evo : prise en charge du nb d occurences actives
# 3.0.0 10-02-2016 - Emmanuel Confrere - Evo : Integration au socle DTSI
# 3.0.1 17-03-2016 - Emmanuel Confrere - Evo : Ajout d information de debug
# 3.1.0 16-06-2017 - Emmanuel Confrere - Evo : Ajout de l option "mode"
# Attente progressive
# Reformulation de l aide.
##----------------------------------------------------------------------------
function fct_unique_exec()
{
local NOM=$1
local OCCURENCES=$2
local MODE=$3
local PID=$$
local WAITING=2
local ELIGIBLE=0
local ELIGIBILITE=0
local FICSEM=""
# -- Marquage
fct_message -debug 0 "<lib:fct_unique_exec> Nom:${NOM} Occ:${OCCURENCES} mode:${MODE} PID:${PID}"
# -- Fixer le nombre maxi d'occurences actives
[ "${OCCURENCES}" = "nowait" -o "${OCCURENCES}" = "wait" ] && MODE=${OCCURENCES} && OCCURENCES=${SH_CPT_SEMAPHORE} || (( ${OCCURENCES} )) || OCCURENCES=${SH_CPT_SEMAPHORE}
# -- Identification de la ressource
[ "${NOM}" = "nowait" -o "${NOM}" = "wait" ] && MODE=${NOM} && NOM=""
(( ${NOM} )) && OCCURENCES=${NOM} && NOM=""
[ -n "${NOM}" ] && FICSEM=`echo ${SH_FICSEM}|sed "s/\.sem$/_${NOM}\.sem/"` || FICSEM=${SH_FICSEM}
echo "${PID}" >> ${FICSEM}
# -- Fixer le mode d execution
[ "${MODE}" = "nowait" ] && MODE=1 || MODE=0
# -- On controle l occupation de la ressource
# -- Le process est-il eligible pour continuer l execution
# -- 0 : Non
# -- 1 : Oui
ELIGIBLE=`head -${OCCURENCES} ${FICSEM}|grep -cw "${PID}"`
# -- Dans le cas ou le process n est pas eligible mais que le mode est nowait
# -- on ne passera pas dans la boucle d attente et on doit par consequent
# -- enleve le process de la liste d attente.
fct_message -debug 1 "<lib:fct_unique_exec> Stack 1 - Nom:${NOM} Occ~:${OCCURENCES} Mode:${MODE} Eligible:${ELIGIBLE}"
(( ${MODE} & ( ${MODE} ^ ${ELIGIBLE} ) )) && fct_libere_exec "@${NOM}@${PID}"
if (( ! (${MODE} | ${ELIGIBLE}) ))
then
# -- La resource est en cours d utilisation, on attend sa liberation...
fct_message -color cyan "Une ou plusieurs occurrence du script ${SH_PROG} est en cours d execution..."
fct_message -nolog -color cyan " - Nombre d occurance active : ${OCCURENCES}"
fct_message -nolog -color blanc " .\c"
while (( ! ${ELIGIBLE} ))
do
fct_message -nolog -color cyan ".\c"
sleep ${WAITING}
(( WAITING++ ))
ELIGIBLE=`head -${OCCURENCES} ${FICSEM}|grep -cw "${PID}"`
ELIGIBILITE=`grep -cw "${PID}" ${FICSEM}`
(( ! ${ELIGIBILITE} )) && echo "${PID}" >> ${FICSEM}
CPID=`head -1 ${FICSEM}`
[ ! -d /proc/${CPID} ] && fct_libere_exec "@${NOM}@${CPID}"
done
fct_message -nolog -color vert "."
fi
return $(( ${MODE} & ( ${MODE} ^ ${ELIGIBLE} ) ))
}
typeset -Ffx fct_unique_exec
# --------------------------------------------------------------------------------------------------------------
function fct_libere_exec()
{
# Objet : Signaler la fin d execution unique d un script shell
#
# Syntaxe : fct_libere_exec
#
local NOM=$1
local PID=$$
local FICSEM
# -- Marquage
fct_message -debug 0 "<lib:fct_libere_exec> Nom:${NOM} PID:${PID}"
[ "${NOM:0:1}" = "@" ] && PID=${NOM##*@} && NOM=${NOM%@*} && NOM=${NOM#@}
[ -n "${NOM}" ] && FICSEM=`echo ${SH_FICSEM}|sed "s/\.sem$/_${NOM}\.sem/"` || FICSEM=${SH_FICSEM}
if [ -f ${FICSEM} ]
then
cat ${FICSEM}|grep -wv "${PID}" > ${FICSEM}.tmp
mv ${FICSEM}.tmp ${FICSEM}
[ ! -s ${FICSEM} ] && rm ${FICSEM}
fi
}
typeset -Ffx fct_libere_exec