diff --git a/apps-unlimited/EBSR12.2onOCI/.gitkeep b/apps-unlimited/EBSR12.2onOCI/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/apps-unlimited/EBSR12.2onOCI/.gitkeep @@ -0,0 +1 @@ + diff --git a/apps-unlimited/EBSR12.2onOCI/AppTier/.gitkeep b/apps-unlimited/EBSR12.2onOCI/AppTier/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/apps-unlimited/EBSR12.2onOCI/AppTier/.gitkeep @@ -0,0 +1 @@ + diff --git a/apps-unlimited/EBSR12.2onOCI/Database/.gitkeep b/apps-unlimited/EBSR12.2onOCI/Database/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/apps-unlimited/EBSR12.2onOCI/Database/.gitkeep @@ -0,0 +1 @@ + diff --git a/apps-unlimited/EBSR12.2onOCI/Database/ChangeHomePath.sh b/apps-unlimited/EBSR12.2onOCI/Database/ChangeHomePath.sh new file mode 100644 index 0000000..c09805a --- /dev/null +++ b/apps-unlimited/EBSR12.2onOCI/Database/ChangeHomePath.sh @@ -0,0 +1,75 @@ +############################################################################# +# ChangeHomePath.sh +# An include script holding the common routine that changes the oracle +# database home path if needed when switching a standby database to primary. +# +# This is an INCLUDE file. It is code to be included in an outer ksh +# script. It just holds the routine ReConfig, which calls the EBS code. +# +# Note: assumes all the database instances are present in gv_instance when +# the check is done in the main script. +# +# Requires user equivalency across all RAC nodes. +# +# No parameters passed in +# +# Rev: +# 8/23/24 Re-formed as a standard routine to access inside different scripts +# 1/15/24 DPresley Created +############################################################################# +# +ReConfig() +{ +LogMsg "Started ReConfig - Database Home Reconfiguration" + +LogMsg "DbName: $DbName" + +# Calling script has the apps password. Need to get the database password +GetLogon $DB_SECRET_NAME +DB_SECRET=$LOGON + +PERLBIN=`dirname $ORACLE_HOME/perl/bin/perl` +LogMsg "PERLBIN = $PERLBIN" + +PATH=${PERLBIN}:${PATH} + +PERL5LIB=$ORACLE_HOME/perl/lib/5.32.0:$ORACLE_HOME/perl/lib/site_perl/5.32.0:$ORACLE_HOME/appsutil/perl + +# Call the EBS script txkSuncDBConfig.pl +LogMsg "Running txkSyncDBConfig.pl" +{ echo "$APPS_SECRET"; } | perl $ORACLE_HOME/appsutil/bin/txkSyncDBConfig.pl \ + -dboraclehome=$ORACLE_HOME \ + -outdir=$ORACLE_HOME/appsutil/log \ + -cdbsid=${ORACLE_SID} \ + -pdbname=${PDB_NAME} \ + -dbuniquename=${DB_UNIQUE_NAME} \ + -israc=YES \ + -virtualhostname=${VIRTUAL_HOSTNAME} \ + -logicalhostname=${LOGICAL_HOSTNAME} \ + -scanhostname=${SCAN_NAME} \ + -scanport=${SCAN_LISTENER_PORT} \ + -dbport=${DB_LISTENER_PORT} \ + -appsuser=${APPS_USERNAME} | tee -a ${LOG_OUT} + + +LogMsg "Running txkCfgUtlfileDir.pl with mode=setUtlFileDir" + +{ echo "$APPS_SECRET"; echo "$DB_SECRET"; } | perl $ORACLE_HOME/appsutil/bin/txkCfgUtlfileDir.pl \ + -contextfile=$CONTEXT_FILE \ + -oraclehome=$ORACLE_HOME \ + -outdir=$ORACLE_HOME/appsutil/log \ + -mode=setUtlFileDir \ + -servicetype=opc | tee -a ${LOG_OUT} + +LogMsg "Running txkCfgUtlfileDir.pl with mode=syncUtlFileDir" + +{ echo "$APPS_SECRET"; } | perl $ORACLE_HOME/appsutil/bin/txkCfgUtlfileDir.pl \ + -contextfile=$CONTEXT_FILE \ + -oraclehome=$ORACLE_HOME \ + -outdir=$ORACLE_HOME/appsutil/log \ + -mode=syncUtlFileDir \ + -servicetype=opc | tee -a ${LOG_OUT} + +LogMsg "Completed ReConfig - Database Home Reconfiguration" +} + diff --git a/apps-unlimited/EBSR12.2onOCI/Database/EBSCFG.env b/apps-unlimited/EBSR12.2onOCI/Database/EBSCFG.env new file mode 100644 index 0000000..a166eb0 --- /dev/null +++ b/apps-unlimited/EBSR12.2onOCI/Database/EBSCFG.env @@ -0,0 +1,69 @@ +# EBSCFG.env +# This environment file is called by scripts on the DB nodes that execute EBS +# TXK commands to configure EBS metadata post switchover or failover. +# The scripts assume logical host names have been implemented for EBS R12.2. +# +# Environment variables in this env file: +# - SCRIPT_DIR: The directory where these scripts reside. +# - THIS_HOSTNAME: The logical host name for THIS host, without the .domain. +# - VIRTUAL_HOSTNAME: The logicalhostname.domain alias for the VIP on THIS node. +# This would be the VIP for the Grid listener or the VIP of a +# dedicated EBS listener. Use the command +# "srvctl config vip -n $HOSTNAME" to get this setting. +# - LOGICAL_HOSTNAME: The logical hostname.domain for THIS server. The EBS +# script txkSyncDBConfig.pl will use this variable to configure EBS +# on THIS node. +# - SCAN_NAME: The SCAN name for THIS cluster. Use the command: "srvctl config +# scan" to obtain the scan name. +# - SCAN_LISTENER_PORT: The listener port number for the SCAN listeners. Use +# the command "srvctl config scan_listener" to get this value. +# - DB_LISTENER_PORT: The listener port number for the database. This can be +# the Grid listener port or the listener port of a dedicated EBS +# listener if one is configured and running. +# - DB_HOSTS: Space-delimited list of network assigned / physical hostnames +# for the EBS RAC database, enclosed in double quotes. +# Do not use logical host names for this list. +# Example: "physicalhost1 physicalhost2 physicalhostN..." +# - CDB_NAME: The name of the database CDB as set by the database parameter +# DB_NAME. +# - DB_UNIQUE_NAME: The database unique name set by the database parameter +# DB_UNIQUE_NAME. +# - PDB_NAME: The name of the PDB that the EBS database resides in. +# - CONTEXT_FILE: $ORACLE_HOME/_.env +# - PDB_TNS_CONNECT_STRING: The TNS connect string for the PDB +# - DB_SECRET_NAME: The name of the secret in the OCI vault holding the +# database EBS_SYSTEM password/credential. +# - APPS_SECRET_NAME: The name of the secret in the OCI vault holding the APPS +# schema password/credential. +# - APPS_USERNAME: The name of the APPS schema, typically "APPS". +# - COMPARTMENT_OCID: The OCID of the OCI compartment that contains the OCI +# vault. +# - LOG_DIR: These scripts will write their execution logs in this directory + +SCRIPT_DIR=/home/oracle/ebscdb/coRoutines + +THIS_HOSTNAME=ebsdb1 +VIRTUAL_HOSTNAME=ebsdb1-vip.ebsdbprivateexa.ebsmaacloud2vcn.oraclevcn.com +LOGICAL_HOSTNAME=ebsdb1.ebsdbprivateexa.ebsmaacloud2vcn.oraclevcn.com +SCAN_NAME=iadexadb-bw5wn-scan.ebsexadbprivate.ebscloudmaavcn.oraclevcn.com + +SCAN_LISTENER_PORT=1521 +DB_LISTENER_PORT=1521 + +DB_HOSTS="iadexadb-bw5wn1 iadexadb-bw5wn2" +CDB_NAME=EBSCDB +DB_UNIQUE_NAME=EBSCDB_9cv_iad + +PDB_NAME=VISPRD +PDB_TNS_CONNECT_STRING=visprd +CONTEXT_FILE=${ORACLE_HOME}/${PDB_NAME}_${THIS_HOSTNAME} + +DB_SECRET_NAME=ebs-db-secret +APPS_SECRET_NAME=ebs-apps-secret +APPS_USERNAME=APPS + +COMPARTMENT_OCID="ocid1.compartment.oc1..aaaaaaaadynzghibxxo362cdebbtkqtuixd5ql24njdk3rd4mtil6qr5mgzq" + +LOG_DIR=${SCRIPT_DIR}/log +TNS_ALIAS=visprd + diff --git a/apps-unlimited/EBSR12.2onOCI/Database/EBS_DB_RoleChange.sh b/apps-unlimited/EBSR12.2onOCI/Database/EBS_DB_RoleChange.sh new file mode 100644 index 0000000..d124ce8 --- /dev/null +++ b/apps-unlimited/EBSR12.2onOCI/Database/EBS_DB_RoleChange.sh @@ -0,0 +1,107 @@ +#!/bin/ksh +############################################################################# +# EBS_DB_RoleChange.sh +# Spawn the scripts to reconfigure EBS on the database RAC nodes if required. +# +# Note: This script blocks when running the txk configuration scripts, so +# errors are caught here instead of floating around in the ether. +# +# Note: If the homes need to change: we're assuming all database instances +# are visible in gv$instance when this is executed. If an instance +# is down, that home will not be reconfigured. +# +# Requires user equivalency across all RAC nodes. +# +# Things to ignore or be aware of: +# stty: standard input: Inappropriate ioctl for device +# The random creation of +DATAC1 in your script directory (bug#: ...) +# Creation of logs in your script directory named mmddhhmm.log +# +# No parameters passed in +# +# Rev: +# 8/28/24 MPratt Simplified, added ksh coroutine for efficiency +# 1/15/24 DPresley Created +############################################################################# +# +. /home/oracle/EBSCDB.env +. ./EBSCFG.env +HostName=$(hostname) +MYHOST=$(hostname) + +. ${CONTEXT_FILE}.env + +# Call the standard functions routine +. $SCRIPT_DIR/stdfuncs.sh + +# Include the common code for reconfiguring the path. This will be +# executed both from this script and from the spawned shell scripts on other DB +. $SCRIPT_DIR/ChangeHomePath.sh + +EnvSetup +LOG_OUT=${LOG_DIR}/${HostName}_EBS_DB_RoleChange_${TS}.log + +LogMsg "EBS_DB_RoleChange.sh: Started" + +GetLogon $APPS_SECRET_NAME +APPS_SECRET=$LOGON + +# Start sqlplus in coroutine, logged in as apps user +LaunchCoroutine APPS $APPS_SECRET $PDB_TNS_CONNECT_STRING + +GetDbName + +sql="select XMLTYPE(t.text).EXTRACT('//ORACLE_HOME/text()').getStringVal() \ +from apps.fnd_oam_context_files t \ + where name = '` echo ${PDB_NAME}`_`echo ${THIS_HOSTNAME}`' \ + and node_name = '`echo ${THIS_HOSTNAME}`' \ + order by last_update_date desc \ + fetch first row only;" +EBS_DB_OH=`ExecSql "${sql}"` + +LogMsg "ORACLE_HOME: $ORACLE_HOME" +LogMsg "EBS_DB_OH: $EBS_DB_OH" + +# Only spawn the jobs if the oracle home path is different +if [ "${ORACLE_HOME}" != "${EBS_DB_OH}" ] +# TESTING: DO IT IF IT'S THE SAME +# if [ "${ORACLE_HOME}" = "${EBS_DB_OH}" ] +then + LogMsg "Oracle home paths are different. Reconfigure hosts" + + # Insert a row for each RAC node, then select those rows to drive the fix scripts. + # Need the rows in the table so the middle tiers can see configuration is not + # done yet across all instances. + + # Are we assuming all instances are up when this executes? Why, yes, we are... + + sql="INSERT INTO apps.xxx_EBS_role_change (host_name,rolechange_date) \ + SELECT host_name, sysdate \ + FROM gv\$instance; + commit;" + ExecSql "${sql}" + + LogMsg "DB_HOSTS: $DB_HOSTS" + LogMsg "MYHOST: $MYHOST" + + # DB_HOSTS is a configuration in your .env file + for i in ${DB_HOSTS} + do + if [ "${i}" == "${MYHOST}" ]; + then + LogMsg "Configuring database homes for EBS on local host ${i}" + ReConfig + else + LogMsg "Configuring database homes for EBS on remote host: ${i}" + LogMsg "ssh -t oracle@${i} cd ${SCRIPT_DIR}; ${SCRIPT_DIR}/callReConfig.sh" + ssh -t oracle@${i} "cd ${SCRIPT_DIR}; ${SCRIPT_DIR}/callReConfig.sh" + fi + + sql="DELETE FROM apps.xxx_EBS_role_change where host_name='${i}'; + commit;" + ExecSql "${sql}" + done +fi + +LogMsg "Completed: EBS_DB_RoleChange.sh." + diff --git a/apps-unlimited/EBSR12.2onOCI/Database/callReConfig.sh b/apps-unlimited/EBSR12.2onOCI/Database/callReConfig.sh new file mode 100644 index 0000000..7e3d4bc --- /dev/null +++ b/apps-unlimited/EBSR12.2onOCI/Database/callReConfig.sh @@ -0,0 +1,58 @@ +#!/bin/ksh +############################################################################# +# callReConfig.sh +# Call the scripts to reconfigure EBS on the database RAC nodes on remote +# hosts. +# +# Requires user equivalency across all RAC nodes. +# +# This script establishes the environment, gets the apps password. +# then executes ReConfig on remote hosts. It's called remotely by +# EBS_DB_RoleChange.sh +# +# Rev: +# 8/29/24 MPratt Created +############################################################################# +# + +# echo "callReConfig.sh: You got in" +# echo "HOSTNAME: $HOSTNAME" +mypath=`pwd` +echo "mypath: $mypath" + +. /home/oracle/EBSCDB.env +. ${mypath}/EBSCFG.env +HostName=$(hostname) + +. ${CONTEXT_FILE}.env + +# Include the standard functions routines +. $SCRIPT_DIR/stdfuncs.sh + +# Include the common code for reconfiguring the path. This holds the +# code that is executed in this script for the DB nodes remote to the main +# driving script. +. $SCRIPT_DIR/ChangeHomePath.sh + +EnvSetup +LOG_OUT=${LOG_DIR}/${HostName}_callReConfig_${TS}.log + +LogMsg "callReConfig.sh: Started" + +# Get the apps password - needs to be set before executing ReConfig +GetLogon $APPS_SECRET_NAME +APPS_SECRET=$LOGON + +# Don't need to do this - not executing sqlplus for anything here +# Start sqlplus in coroutine, logged in as apps user +# LaunchCoroutine APPS $APPS_SECRET $PDB_TNS_CONNECT_STRING + +# for this script, ok to substitute HostName for DbName, which is used +# in LogMsg (else would need to launch the coroutine) +# GetDbName +DbName=$HostName + +ReConfig + +LogMsg "callReConfig.sh: Completed." + diff --git a/apps-unlimited/EBSR12.2onOCI/Database/stdfuncs.sh b/apps-unlimited/EBSR12.2onOCI/Database/stdfuncs.sh new file mode 100644 index 0000000..4a214ad --- /dev/null +++ b/apps-unlimited/EBSR12.2onOCI/Database/stdfuncs.sh @@ -0,0 +1,371 @@ +############################################################################# +# std_funcs.sh +# Collection of standard functions. +# +# Rev: +# 8/13/24 MPratt Updated for simple cloud tooling +# 7/19/99 MPratt added GetLogon +# 1/17/96 MPratt added MultiThread and CkRun +# 8/23/95 MPratt created +############################################################################# +# GetLogon: +# Get the password for the user secret name passed in. Set the variable +# LOGON. In the calling routine, set the intended password variable. +# +############################################################################# + +GetLogon() +{ +uname=$1 + +SECRET_OCID=$(oci vault secret list -c $COMPARTMENT_OCID --raw-output --query "data[?\"secret-name\" == '$uname'].id | [0]") + +LOGON=$(oci secrets secret-bundle get --raw-output --secret-id $SECRET_OCID --query "data.\"secret-bundle-content\".content" | base64 -d ) + +if [ $? != 0 ]; then + LogMsg "GetLogon: Failed." + LogMsg "Compartment: $COMPARTMENT_OCID" + LogMsg "User name: $uname" + exit 1 +fi +} + +############################################################################# +# EnvSetup: +# Set up the unix and oracle environment as needed... +# +# Do we need this? Hohw should it be adjusted for modern era? +# Removed export of ORAENV_ASK=NO +# +############################################################################# + +EnvSetup() +{ +# set TS to the timestamp. Used to create the output directory for the run. +TS=`date +"%Y%m%d_%H%M%S"` + +# Set up the oracle environment. +# ORAENV_ASK=NO; . oraenv +} + +############################################################################# +# GetDbName +# Get the database name for this oracle sid +# +# Input: None +# Output: Sets DbName variable +# Return: None +############################################################################# + +GetDbName() +{ + sql="select name from v\$database;" + DbName=`ExecSql "${sql}"` +} + +############################################################################# +# LaunchCoroutine: +# Start a sqlplus session to pipe commands to from this shell session. +# +# Input: DB password secret needs to be set prior to calling +# Output: None, but the coroutine stays up and running +# Return: exits if error is detected. +############################################################################# + +LaunchCoroutine() +{ +uname=$1 +pwd=$2 +cxHost=$3 + +cxString=$uname/$pwd@$cxHost + +if [[ ! "$uname" || ! "$pwd" || ! "$cxHost" ]]; then + LogMsg "Usage: LaunchCoroutine user_name password host" + LogMsg "User name: $uname" + LogMsg "Password: $pwd" + LogMsg "Host: $cxHost" + LogMsg "Connection string: $cxString" + exit 1 +fi + +# Verify the Oracle connection +sqlplus -silent <$TMP_FILE 2>&1 +$cxString +! + +if [ $? != 0 ]; then + LogMsg "LaunchCoroutine: Unable to connect to Oracle." + LogMsg "LaunchCoroutine: Verify password, state of database" + cat $TMP_FILE | LogMsg + exit 1 +fi + +# Launch the coroutine itself. +sqlplus -s |& +echo -e "${cxString}" >&p +echo -e "set scan off\n" >&p +echo -e "set heading off\n" >&p +echo -e "set feedback off\n" >&p +echo -e "set pagesize 0\n" >&p +echo -e "set linesize 2000\n" >&p +echo -e "set long 65535\n" >&p +echo -e "select '<-DONE->' from dual;\n" >&p + +tmp="$IFS" +IFS="" + +# read from the coroutine's output 'til you see <-DONE-> +while [ "1" ]; do + read answer <&p + if [ "$answer" = "<-DONE->" ]; then + break + fi +done + + +IFS="$tmp" + +rm $TMP_FILE + +} + + +############################################################################# +# ExecSql +# Send a SQL statement to the sqlplus coroutine; return the result to the +# calling routine. +# +# Input: sql statement +# Output: result of sql statement +# Return: none +############################################################################# + +ExecSql () +{ +# send the statement to the coroutine with the "-p" + echo -e "$1\n" >&p + echo -e "select '<-DONE->' from dual;\n" >&p + + tmp="$IFS" + IFS="" + +# read from the coroutine's output 'til you see <-DONE-> + while [ "1" ]; do + read answer <&p + + if [ "$answer" = "<-DONE->" ]; then + break + else + echo -e "$answer" + fi + done + + IFS="$tmp" +} + + +############################################################################# +# DbConnect +# Connect to a different database. This needs a different routine than +# ExecSql. +# +# Input: connect string +# Output: result of sql statement +# Return: none +############################################################################# + +DbConnect () +{ + +# send the statement to the coroutine with the "-p" + printf -p "$1" + printf -p "select '<-DONE->' from dual;" + + tmp="$IFS" + IFS="" + +# read from the coroutine's output 'til you see <-DONE-> + while [ "1" ]; do + read -p answer + + if [ "$answer" = "<-DONE->" ]; then + printf "$answer" + break + fi + + if [ "$answer" = "ORA-03114: not connected to ORACLE" ]; then + LogMsg "DbConnect: ERROR: $answer" + exit 1 + fi + + if [ "$answer" = "ERROR: ORA-01034: ORACLE not available" ]; then + LogMsg "DbConnect: ERROR: $answer" + exit 1 + fi + + done + + IFS="$tmp" +} + + +############################################################################## +# +# Description: Echo a message to stdout and the run's log file. +# +# Usage: LogMsg "message text" +# +# Input: Message text +# Note: If message text = "-p", then input is read from stdin +# (so you can pipe to this). +# +# Output: Writes the timestamp, host name, database name, and message to +# stdout and to LOG_OUT. Requires LOG_OUT be already defined +# +# Return: None +# +############################################################################## + +LogMsg () +{ + LogMsgTimestamp=`date +"%m%d %T"` + +# If they are piping the message in to print from a command +# (eg, cat file | LogMsg), this requires resetting the interfield +# separator, After that, we read the message piece by piece from stdin. + if [ "$1" = "-p" ]; then + tmp="$IFS" + IFS="" + while read message + do + printf "${LogMsgTimestamp}|${HostName}|${DbName}| $message\n" + if [ ! -z "$LOG_OUT" ]; then + printf "${LogMsgTimestamp}|${HostName}|${DbName}| $message\n" >> $LOG_OUT + fi + done + IFS="$tmp" + +# Not piping anything to the message - just text passed straight in + else + printf "${LogMsgTimestamp}|${HostName}|${DbName}| $1\n" + if [ ! -z "$LOG_OUT" ]; then + printf "${LogMsgTimestamp}|${HostName}|${DbName}| $1\n" >> $LOG_OUT + fi + fi +} + +############################################################################## +# CkRun +# monitor running processes to see if any are still running. +# +# Input: 1: Unique thing to check on a ps line (required) +# 2: number of seconds to sleep between checks (required) +# 3: S if the run is to be relatively Silent +# Output: None. +# Return: Returns control when all monitored processes are complete. +############################################################################## +CkRun() +{ +ckit=$1 +thislong=$2 +silent=$3 +LogMsg "CkRun: Monitoring for $ckit" + +if [ "$ckit" = "" ] || [ "$thislong" = "" ]; then + LogMsg: "CkRun: ERROR: Insufficient arguments." + exit 1 +fi + +while true +do + if [ "$silent" != "S" ]; then + ps -ef | grep $ckit | grep -v grep | grep -v ckrun + fi + matches=`ps -ef | grep $ckit | grep $$ | grep -v grep | wc -l` + ts=`date +%m/%d/%y.%H:%M:%S` + printf "$ts: $matches matches" + printf "===================================================================" + if [ $matches = 0 ]; then + break; + fi + sleep $thislong +done + +LogMsg "CkRun: Returning control to calling routine." +} + + +############################################################################## +# MultiThread +# Submit multiple tasks in the background. "Mark time" until they are all +# complete, then return control to the calling routine. +# +# You provide a file which has command lines for the tasks, one task per line. +# These lines are "nohup'd" and run in the background. Control is returned +# to your calling routine when all the tasks are complete. +# +# You limit the number of tasks which can be run at once, and you provide a +# unique piece of info to "grep" for on a ps -ef line, to use to count the +# number of running tasks and determine whether or not there are tasks still +# running. +# +# Possible "gotchas": if you are vi'ing or otherwise accessing something +# which puts your "unique" grep field on the ps command line, this routine +# WILL NOT return control to the calling routine! +# +# Input: 1: name of a file which holds commands to run. one line per command. +# 2: max # processes to run at once +# 3: unique part of the command line to "grep" for when determining +# how many of these processes are running +# 4: number of seconds to sleep between checks for task completion +# 5: verbose mode (yes/no) +# Output: Your tasks are complete. +# Return: exit 1 if incomplete info is provided. +############################################################################## +MultiThread() +{ +tasks=$1 +max_processes=$2 +differentiator=$3 +sleep_time=$4 + +LogMsg "MultiThread: Starting multi-threaded execution of $tasks." +LogMsg "MultiThread: No more than $max_processes will run at once." +LogMsg "MultiThread: Using $differentiator for unique ps search." + +# read the tasks from the file. for each one: +cat $tasks | while read i +do + LogMsg "MultiThread: Starting $i" + nohup $i & +# count the number of jobs running already. + matches=`ps -ef | grep $differentiator | grep $$ | grep -v grep | \ + grep -v ckrun | wc -l` +# if the number of jobs running is >= max_processes, fall into this loop. +# otherwise go through the outer loop again to kick off another job. + until [ $matches -lt $max_processes ] + do + sleep $sleep_time + matches=`ps -ef | grep $differentiator | grep $$ | grep -v grep | \ + grep -v ckrun | wc -l` + LogMsg "MultiThread: $matches tasks running..." + done +done + +# Run the monitor. It finishes when the tasks are done. Need this, +# even though the jobs are kicked off when needed, as when the above loop +# is done there are still tasks running. We can't return control to the +# calling routine until they are complete. +CkRun $differentiator $sleep_time S + +LogMsg "MultiThread: Tasks complete. Returning control to calling routine." +} + + +############################################################################## +# initialize common variables. this is NOT inside a function so it gets +# executed right away. +############################################################################## +TMP=/tmp +TMP_FILE=$TMP/TMP_FILE.$$