recursive subroutine ESMF_CompExecute(compp, method, &
importState, exportState, clock, syncflag, phase, port, timeout, userRc, rc)
!
!
! !ARGUMENTS:
type(ESMF_CompClass), pointer :: compp
type(ESMF_Method_Flag), intent(in) :: method
type(ESMF_State), intent(inout), optional :: importState
type(ESMF_State), intent(inout), optional :: exportState
type(ESMF_Clock), intent(in), optional :: clock
type(ESMF_Sync_Flag), intent(in), optional :: syncflag
integer, intent(in), optional :: phase
integer, intent(in), optional :: port
integer, intent(in), optional :: timeout
integer, intent(out), optional :: userRc
integer, intent(out), optional :: rc
!
! !DESCRIPTION:
! Component Execute method used by GridComp and CplComp for:
! * Initialize,
! * Run,
! * Finalize,
! * ReadRestart,
! * WriteRestart.
!
! Call into the associated user code for a component's method.
!
! The arguments are:
! \begin{description}
!
! \item[compp]
! Component to call Initialization routine for.
! \item[method]
! One of the ESMF Component methods. See section \ref{const:methods}
! for a complete list of valid methods.
! \item[{[importState]}]
! Import data for component method.
! \item[{[exportState]}]
! Export data for component method.
! \item[{[clock]}]
! External clock for passing in time information.
! \item[{[syncflag]}]
! Blocking behavior of this method call. See section \ref{const:sync}
! for a list of valid blocking options. Default option is
! {\tt ESMF\_SYNC\_VASBLOCKING} which blocks PETs and their spawned off threads
! across each VAS.
! \item[{[phase]}]
! The phase of a multi-phase method. Default is 1.
! \item[{[port]}]
! Port number. Only used for ESMF\_METHOD\_SERVICELOOP.
! \item[{[timeout]}]
! Time out in seconds.
! \item[{[userRc]}]
! Return code set by {\tt userRoutine} before returning.
! \item[{[rc]}]
! Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
! \end{description}
!
!EOPI
!------------------------------------------------------------------------------
integer :: localrc ! local return code
integer :: localUserRc ! return code from user code
type(ESMF_Sync_Flag) :: blocking ! local blocking flag
type(ESMF_VM) :: vm ! VM for current context
integer :: phaseArg
integer :: portArg
integer :: timeoutArg
real(ESMF_KIND_R8) :: usedTime
character(160) :: msgString
! dummys that will provide initializer values if args are not present
type(ESMF_State) :: dummyis, dummyes
type(ESMF_Clock) :: dummyclock
type(ESMF_Status) :: baseStatus
! Initialize return code; assume not implemented until success is certain
localrc = ESMF_RC_NOT_IMPL
if (present(rc)) rc = ESMF_RC_NOT_IMPL
! Test incoming compp object
if (.not.associated(compp)) then
call ESMF_LogSetError(ESMF_RC_OBJ_BAD, &
msg="Not a valid pointer to ESMF Component object", &
ESMF_CONTEXT, rcToReturn=rc)
return
endif
! Check init status of arguments
ESMF_INIT_CHECK_DEEP(ESMF_CompClassGetInit, compp, rc)
call ESMF_BaseGetStatus(compp%base, baseStatus, rc=localrc)
if (ESMF_LogFoundError(localrc, &
ESMF_ERR_PASSTHRU, &
ESMF_CONTEXT, rcToReturn=rc)) return
if (baseStatus /= ESMF_STATUS_READY) then
call ESMF_LogSetError(ESMF_RC_OBJ_BAD, &
msg="uninitialized or destroyed Component object", &
ESMF_CONTEXT, rcToReturn=rc)
return
endif
! check if this is a supported combination of conditions
if (compp%vm_released.and. &
(method/=ESMF_METHOD_WAIT).and. &
(method/=ESMF_METHOD_NONE)) then
call ESMF_LogSetError(ESMF_RC_OBJ_BAD, &
msg="cannot call this method while the component is executing", &
ESMF_CONTEXT, rcToReturn=rc)
return
endif
! set the default mode to ESMF_SYNC_VASBLOCKING
if (present(syncflag)) then
blocking = syncflag
else
blocking = ESMF_SYNC_VASBLOCKING
endif
! supply default objects if unspecified by the caller
if (present(importState)) then
compp%is = importState
compp%compStatus%isIsPresent = .true.
else
! use dummy variable
compp%is = dummyis
endif
if (present(exportState)) then
compp%es = exportState
compp%compStatus%esIsPresent = .true.
else
! use dummy variable
compp%es = dummyes
endif
! and something for clocks?
if (present(clock)) then
compp%argclock = clock
else
! use dummy variable -> set to null pointer since this is deep C++ impl.
call ESMF_ClockSetThis(dummyclock, ESMF_NULL_POINTER, localrc)
if (ESMF_LogFoundError(localrc, &
ESMF_ERR_PASSTHRU, &
ESMF_CONTEXT, rcToReturn=rc)) return
compp%argclock = dummyclock
endif
! set phase and port number
phaseArg = 1 ! default phase
if (present(phase)) phaseArg = phase
if ((method==ESMF_METHOD_SERVICELOOP) .or. &
(method==ESMF_METHOD_SERVICELOOPIC)) then
! deal with special phase/port argument combination
if (phaseArg /= 1) then
call ESMF_LogSetError(ESMF_RC_ARG_BAD, &
msg="Phase must be 1 for ServiceLoop() call.", &
ESMF_CONTEXT, rcToReturn=rc)
return
endif
if (present(port)) then
if (port < 1024 .or. port > 65535) then
call ESMF_LogSetError(ESMF_RC_ARG_BAD, &
msg="The 'port' argument is outside valid range [1024, 65535]", &
ESMF_CONTEXT, rcToReturn=rc)
return
endif
portArg = port ! valid port number
else
portArg = -1 ! indicate that no port was specified
endif
else
! all other component methods have regular phase arguments
if (present(port)) then
call ESMF_LogSetError(ESMF_RC_ARG_BAD, &
msg="Port is only allowed for ServiceLoop() call.", &
ESMF_CONTEXT, rcToReturn=rc)
return
endif
portArg = -1 ! indicate that no port was specified
endif
! Timeout argument
timeoutArg = 0; ! default timeout to flag issue if it is really used later
if (present(timeout)) then
if (timeout < 0) then
call ESMF_LogSetError(ESMF_RC_ARG_BAD, &
msg="The 'timeout' argument must be positive", &
ESMF_CONTEXT, rcToReturn=rc)
return
endif
timeoutArg = timeout ! valid timeout
endif
! Wrap comp so it's passed to C++ correctly.
compp%compw%compp => compp
ESMF_INIT_SET_CREATED(compp%compw)
compp%compw%isNamedAlias = .false.
! Set up the arguments
if (compp%iAmParticipant) then
! only call this on PETs that participate
call c_ESMC_FTableSetStateArgs(compp%ftable, method, phaseArg, &
compp%compw, compp%is, compp%es, compp%argclock, compp%compTunnel, &
localrc)
if (ESMF_LogFoundError(localrc, &
ESMF_ERR_PASSTHRU, &
ESMF_CONTEXT, rcToReturn=rc)) return
endif
localUserRc = ESMF_SUCCESS ! initialize to success
! pass back the initialized value of userRc, just in case of a bail out
if (present(userRc)) userRc = localUserRc
! All of the participating PETs must call in, but also non-participating
! PETs that hold a valid VM and show up here enter the callback mechanism.
if (compp%iAmParticipant .or. compp%compStatus%vmIsPresent) then
! store the start time
call ESMF_VMWtime(compp%startTime, rc=localrc)
if (ESMF_LogFoundError(localrc, &
ESMF_ERR_PASSTHRU, &
ESMF_CONTEXT, rcToReturn=rc)) return
! callback into user code
#if 0
write (msgString,*) "ESMF_CompExecute(), calling c_ESMC_FTableCallEntryPointVM(): timeoutArg=",timeoutArg
call ESMF_LogWrite(msgString, ESMF_LOGMSG_DEBUG, rc=localrc)
#endif
call c_ESMC_FTableCallEntryPointVM(compp%compw, compp%vm_parent, &
compp%vmplan, compp%vm_info, compp%vm_cargo, compp%ftable, method, &
phaseArg, portArg, timeoutArg, compp%vm_recursionCount, localrc)
if (ESMF_LogFoundError(localrc, &
ESMF_ERR_PASSTHRU, &
ESMF_CONTEXT, rcToReturn=rc)) return
! For threaded VMs (single- or multi-threaded) the child VM will
! now be running concurrently with the parent VM.
! Also for component tunnels, the actual component will now be executing
! concurrently with the dual component that came in to this call.
! wait for blocking modes
if (blocking == ESMF_SYNC_VASBLOCKING .or. blocking == ESMF_SYNC_BLOCKING) then
! wait for all child PETs that run in this parent's PET VAS to finish
! determine how long the component has been released already
call ESMF_VMWTime(usedTime, rc=localrc)
if (ESMF_LogFoundError(localrc, &
ESMF_ERR_PASSTHRU, &
ESMF_CONTEXT, rcToReturn=rc)) return
usedTime = usedTime - compp%startTime
! allow remaining time for timeout, but at least 1 second to wrap up
timeoutArg = max(timeoutArg - int(usedTime), 1)
#if 0
write (msgString,*) "ESMF_CompExecute(), calling c_ESMC_CompWait(): usedTime=",usedTime,"timeoutArg=",timeoutArg
call ESMF_LogWrite(msgString, ESMF_LOGMSG_DEBUG, rc=localrc)
#endif
call c_ESMC_CompWait(compp%vm_parent, compp%vmplan, compp%vm_info, &
compp%vm_cargo, timeoutArg, compp%vm_recursionCount, localUserRc, &
localrc)
! localUserRc - return code of registered user callback method
! localrc - return code of ESMF internal callback stack
if (ESMF_LogFoundError(localrc, &
ESMF_ERR_PASSTHRU, &
ESMF_CONTEXT, rcToReturn=rc)) return
endif
endif
! sync PETs according to blocking mode
if (blocking == ESMF_SYNC_NONBLOCKING) then
compp%vm_released = .true.
else
compp%vm_released = .false. ! indicate child VM has been caught
! for ESMF_SYNC_BLOCKING _all_ parent PETs will be synced on exit
if (blocking == ESMF_SYNC_BLOCKING) then
! the current context _is_ the parent context...
call ESMF_VMGetCurrent(vm=vm, rc=localrc) ! determine current VM
if (ESMF_LogFoundError(localrc, &
ESMF_ERR_PASSTHRU, &
ESMF_CONTEXT, rcToReturn=rc)) return
call ESMF_VMBarrier(vm=vm, rc=localrc) ! barrier across parent VM
if (ESMF_LogFoundError(localrc, &
ESMF_ERR_PASSTHRU, &
ESMF_CONTEXT, rcToReturn=rc)) return
endif
endif
! pass back userRc
if (present(userRc)) userRc = localUserRc
! Return successfully
if (present(rc)) rc = ESMF_SUCCESS
end subroutine ESMF_CompExecute